~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to database/schema/patch-2208-75-0.sql

MergeĀ fromĀ trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
 
2
 
SET client_min_messages=ERROR;
3
 
 
4
 
TRUNCATE BugSummary;
5
 
TRUNCATE BugSummaryJournal;
6
 
 
7
 
DROP INDEX bugsummary__dimensions__unique;
8
 
DROP INDEX bugsummary__full__idx;
9
 
 
10
 
ALTER TABLE BugSummary
11
 
    -- Add a missing foreign key constraint we were unable to add live.
12
 
    -- Person table is always being read, so locks are never acquired.
13
 
    ADD CONSTRAINT bugsummaryjournal_viewed_by_fkey
14
 
        FOREIGN KEY(viewed_by) REFERENCES Person ON DELETE CASCADE,
15
 
    ADD COLUMN importance integer NOT NULL,
16
 
    ADD COLUMN has_patch boolean NOT NULL,
17
 
    ADD COLUMN fixed_upstream boolean NOT NULL;
18
 
 
19
 
ALTER TABLE BugSummaryJournal
20
 
    ADD COLUMN importance integer NOT NULL,
21
 
    ADD COLUMN has_patch boolean NOT NULL,
22
 
    ADD COLUMN fixed_upstream boolean NOT NULL;
23
 
 
24
 
DROP VIEW CombinedBugSummary;
25
 
CREATE VIEW CombinedBugSummary AS (
26
 
    SELECT
27
 
        id, count, product, productseries, distribution, distroseries,
28
 
        sourcepackagename, viewed_by, tag, status, milestone,
29
 
        importance, has_patch, fixed_upstream
30
 
    FROM BugSummary
31
 
    UNION ALL
32
 
    SELECT
33
 
        -id as id, count, product, productseries, distribution, distroseries,
34
 
        sourcepackagename, viewed_by, tag, status, milestone,
35
 
        importance, has_patch, fixed_upstream
36
 
    FROM BugSummaryJournal);
37
 
 
38
 
 
39
 
INSERT INTO BugSummary (
40
 
    count, product, productseries, distribution, distroseries,
41
 
    sourcepackagename, viewed_by, tag, status, importance, has_patch,
42
 
    fixed_upstream, milestone)
43
 
WITH
44
 
    -- kill dupes
45
 
    relevant_bug AS (SELECT * FROM bug where duplicateof is NULL),
46
 
 
47
 
    -- (bug.id, tag) for all bug-tag pairs plus (bug.id, NULL) for all bugs
48
 
    bug_tags AS (
49
 
        SELECT relevant_bug.id, NULL::text AS tag FROM relevant_bug
50
 
        UNION
51
 
        SELECT relevant_bug.id, tag
52
 
        FROM relevant_bug INNER JOIN bugtag ON relevant_bug.id=bugtag.bug),
53
 
 
54
 
    -- (bug.id, NULL) for all public bugs + (bug.id, viewer) for all
55
 
    -- (subscribers+assignee) on private bugs
56
 
    bug_viewers AS (
57
 
        SELECT relevant_bug.id, NULL::integer AS person
58
 
        FROM relevant_bug WHERE NOT relevant_bug.private
59
 
        UNION
60
 
        SELECT relevant_bug.id, assignee AS person
61
 
        FROM relevant_bug
62
 
        INNER JOIN bugtask ON relevant_bug.id=bugtask.bug
63
 
        WHERE relevant_bug.private and bugtask.assignee IS NOT NULL
64
 
        UNION
65
 
        SELECT relevant_bug.id, bugsubscription.person
66
 
        FROM relevant_bug INNER JOIN bugsubscription
67
 
            ON bugsubscription.bug=relevant_bug.id WHERE relevant_bug.private),
68
 
 
69
 
    -- (bugtask.(bug, product, productseries, distribution, distroseries,
70
 
    -- sourcepackagename, status, milestone) for all bugs + the same with
71
 
    -- sourcepackage squashed to NULL)
72
 
    tasks AS (
73
 
        SELECT
74
 
            bug, product, productseries, distribution, distroseries,
75
 
            sourcepackagename, status, importance,
76
 
            (EXISTS
77
 
                (SELECT TRUE
78
 
                FROM BugTask AS RelatedBugTask
79
 
                WHERE RelatedBugTask.bug = BugTask.bug
80
 
                AND RelatedBugTask.id != BugTask.id
81
 
                AND ((RelatedBugTask.bugwatch IS NOT NULL
82
 
                        AND RelatedBugTask.status IN (17, 25, 30))
83
 
                        OR (RelatedBugTask.product IS NOT NULL
84
 
                            AND RelatedBugTask.bugwatch IS NULL
85
 
                            AND RelatedBugTask.status IN (25, 30))))
86
 
                ) as fixed_upstream, milestone
87
 
        FROM bugtask
88
 
        UNION
89
 
        SELECT DISTINCT ON (
90
 
            bug, product, productseries, distribution, distroseries,
91
 
            sourcepackagename, milestone)
92
 
            bug, product, productseries, distribution, distroseries,
93
 
            NULL::integer as sourcepackagename,
94
 
            status, importance,
95
 
            (EXISTS
96
 
                (SELECT TRUE
97
 
                FROM BugTask AS RelatedBugTask
98
 
                WHERE RelatedBugTask.bug = BugTask.bug
99
 
                AND RelatedBugTask.id != BugTask.id
100
 
                AND ((RelatedBugTask.bugwatch IS NOT NULL
101
 
                        AND RelatedBugTask.status IN (17, 25, 30))
102
 
                        OR (RelatedBugTask.product IS NOT NULL
103
 
                            AND RelatedBugTask.bugwatch IS NULL
104
 
                            AND RelatedBugTask.status IN (25, 30))))
105
 
                ) as fixed_upstream, milestone
106
 
        FROM bugtask where sourcepackagename IS NOT NULL)
107
 
 
108
 
    -- Now combine
109
 
    SELECT
110
 
        count(*), product, productseries, distribution, distroseries,
111
 
        sourcepackagename, person, tag, status, importance,
112
 
        latest_patch_uploaded IS NOT NULL AS has_patch, fixed_upstream,
113
 
        milestone
114
 
    FROM relevant_bug
115
 
    INNER JOIN bug_tags ON relevant_bug.id=bug_tags.id
116
 
    INNER JOIN bug_viewers ON relevant_bug.id=bug_viewers.id
117
 
    INNER JOIN tasks on tasks.bug=relevant_bug.id
118
 
    GROUP BY
119
 
        product, productseries, distribution, distroseries,
120
 
        sourcepackagename, person, tag, status, importance, has_patch,
121
 
        fixed_upstream, milestone;
122
 
 
123
 
 
124
 
CREATE INDEX bugsummary__full__idx ON BugSummary (
125
 
    tag, status, product, productseries, distribution,
126
 
    distroseries, sourcepackagename, viewed_by, milestone,
127
 
    importance, has_patch, fixed_upstream);
128
 
CREATE UNIQUE INDEX bugsummary__product__unique
129
 
    ON BugSummary(
130
 
        product, status, importance, has_patch, fixed_upstream,
131
 
        COALESCE(tag, ''), COALESCE(milestone, -1), COALESCE(viewed_by, -1))
132
 
    WHERE product IS NOT NULL;
133
 
CREATE UNIQUE INDEX bugsummary__productseries__unique
134
 
    ON BugSummary(
135
 
        productseries, status, importance, has_patch, fixed_upstream,
136
 
        COALESCE(tag, ''), COALESCE(milestone, -1), COALESCE(viewed_by, -1))
137
 
    WHERE productseries IS NOT NULL;
138
 
CREATE UNIQUE INDEX bugsummary__distribution__unique
139
 
    ON BugSummary(
140
 
        distribution, status, importance, has_patch, fixed_upstream,
141
 
        COALESCE(sourcepackagename, -1),
142
 
        COALESCE(tag, ''), COALESCE(milestone, -1), COALESCE(viewed_by, -1))
143
 
    WHERE distribution IS NOT NULL;
144
 
CREATE UNIQUE INDEX bugsummary__distroseries__unique
145
 
    ON BugSummary(
146
 
        distroseries, status, importance, has_patch, fixed_upstream,
147
 
        COALESCE(sourcepackagename, -1),
148
 
        COALESCE(tag, ''), COALESCE(milestone, -1), COALESCE(viewed_by, -1))
149
 
    WHERE distroseries IS NOT NULL;
150
 
 
151
 
 
152
 
CREATE OR REPLACE FUNCTION bugsummary_journal_ins(d bugsummary)
153
 
RETURNS VOID
154
 
LANGUAGE plpgsql AS
155
 
$$
156
 
BEGIN
157
 
    IF d.count <> 0 THEN
158
 
        INSERT INTO BugSummaryJournal (
159
 
            count, product, productseries, distribution,
160
 
            distroseries, sourcepackagename, viewed_by, tag,
161
 
            status, milestone,
162
 
            importance, has_patch, fixed_upstream)
163
 
        VALUES (
164
 
            d.count, d.product, d.productseries, d.distribution,
165
 
            d.distroseries, d.sourcepackagename, d.viewed_by, d.tag,
166
 
            d.status, d.milestone,
167
 
            d.importance, d.has_patch, d.fixed_upstream);
168
 
    END IF;
169
 
END;
170
 
$$;
171
 
 
172
 
COMMENT ON FUNCTION bugsummary_journal_ins(bugsummary) IS
173
 
'Add an entry into BugSummaryJournal';
174
 
 
175
 
 
176
 
CREATE OR REPLACE FUNCTION bugsummary_rollup_journal() RETURNS VOID
177
 
LANGUAGE plpgsql VOLATILE
178
 
SECURITY DEFINER SET search_path TO public AS
179
 
$$
180
 
DECLARE
181
 
    d bugsummary%ROWTYPE;
182
 
    max_id integer;
183
 
BEGIN
184
 
    -- Lock so we don't content with other invokations of this
185
 
    -- function. We can happily lock the BugSummary table for writes
186
 
    -- as this function is the only thing that updates that table.
187
 
    -- BugSummaryJournal remains unlocked so nothing should be blocked.
188
 
    LOCK TABLE BugSummary IN ROW EXCLUSIVE MODE;
189
 
 
190
 
    SELECT MAX(id) INTO max_id FROM BugSummaryJournal;
191
 
 
192
 
    FOR d IN
193
 
        SELECT
194
 
            NULL as id,
195
 
            SUM(count),
196
 
            product,
197
 
            productseries,
198
 
            distribution,
199
 
            distroseries,
200
 
            sourcepackagename,
201
 
            viewed_by,
202
 
            tag,
203
 
            status,
204
 
            milestone,
205
 
            importance,
206
 
            has_patch,
207
 
            fixed_upstream
208
 
        FROM BugSummaryJournal
209
 
        WHERE id <= max_id
210
 
        GROUP BY
211
 
            product, productseries, distribution, distroseries,
212
 
            sourcepackagename, viewed_by, tag, status, milestone,
213
 
            importance, has_patch, fixed_upstream
214
 
        HAVING sum(count) <> 0
215
 
    LOOP
216
 
        IF d.count < 0 THEN
217
 
            PERFORM bug_summary_dec(d);
218
 
        ELSIF d.count > 0 THEN
219
 
            PERFORM bug_summary_inc(d);
220
 
        END IF;
221
 
    END LOOP;
222
 
 
223
 
    DELETE FROM BugSummaryJournal WHERE id <= max_id;
224
 
END;
225
 
$$;
226
 
 
227
 
CREATE OR REPLACE FUNCTION bug_summary_dec(bugsummary) RETURNS VOID
228
 
LANGUAGE SQL AS
229
 
$$
230
 
    -- We own the row reference, so in the absence of bugs this cannot
231
 
    -- fail - just decrement the row.
232
 
    UPDATE BugSummary SET count = count + $1.count
233
 
    WHERE
234
 
        product IS NOT DISTINCT FROM $1.product
235
 
        AND productseries IS NOT DISTINCT FROM $1.productseries
236
 
        AND distribution IS NOT DISTINCT FROM $1.distribution
237
 
        AND distroseries IS NOT DISTINCT FROM $1.distroseries
238
 
        AND sourcepackagename IS NOT DISTINCT FROM $1.sourcepackagename
239
 
        AND viewed_by IS NOT DISTINCT FROM $1.viewed_by
240
 
        AND tag IS NOT DISTINCT FROM $1.tag
241
 
        AND status IS NOT DISTINCT FROM $1.status
242
 
        AND milestone IS NOT DISTINCT FROM $1.milestone
243
 
        AND importance IS NOT DISTINCT FROM $1.importance
244
 
        AND has_patch IS NOT DISTINCT FROM $1.has_patch
245
 
        AND fixed_upstream IS NOT DISTINCT FROM $1.fixed_upstream;
246
 
    -- gc the row (perhaps should be garbo but easy enough to add here:
247
 
    DELETE FROM bugsummary
248
 
    WHERE
249
 
        count=0
250
 
        AND product IS NOT DISTINCT FROM $1.product
251
 
        AND productseries IS NOT DISTINCT FROM $1.productseries
252
 
        AND distribution IS NOT DISTINCT FROM $1.distribution
253
 
        AND distroseries IS NOT DISTINCT FROM $1.distroseries
254
 
        AND sourcepackagename IS NOT DISTINCT FROM $1.sourcepackagename
255
 
        AND viewed_by IS NOT DISTINCT FROM $1.viewed_by
256
 
        AND tag IS NOT DISTINCT FROM $1.tag
257
 
        AND status IS NOT DISTINCT FROM $1.status
258
 
        AND milestone IS NOT DISTINCT FROM $1.milestone
259
 
        AND importance IS NOT DISTINCT FROM $1.importance
260
 
        AND has_patch IS NOT DISTINCT FROM $1.has_patch
261
 
        AND fixed_upstream IS NOT DISTINCT FROM $1.fixed_upstream;
262
 
    -- If its not found then someone else also dec'd and won concurrently.
263
 
$$;
264
 
 
265
 
CREATE OR REPLACE FUNCTION bug_summary_inc(d bugsummary) RETURNS VOID
266
 
LANGUAGE plpgsql AS
267
 
$$
268
 
BEGIN
269
 
    -- Shameless adaption from postgresql manual
270
 
    LOOP
271
 
        -- first try to update the row
272
 
        UPDATE BugSummary SET count = count + d.count
273
 
        WHERE
274
 
            product IS NOT DISTINCT FROM d.product
275
 
            AND productseries IS NOT DISTINCT FROM d.productseries
276
 
            AND distribution IS NOT DISTINCT FROM d.distribution
277
 
            AND distroseries IS NOT DISTINCT FROM d.distroseries
278
 
            AND sourcepackagename IS NOT DISTINCT FROM d.sourcepackagename
279
 
            AND viewed_by IS NOT DISTINCT FROM d.viewed_by
280
 
            AND tag IS NOT DISTINCT FROM d.tag
281
 
            AND status IS NOT DISTINCT FROM d.status
282
 
            AND milestone IS NOT DISTINCT FROM d.milestone
283
 
            AND importance IS NOT DISTINCT FROM d.importance
284
 
            AND has_patch IS NOT DISTINCT FROM d.has_patch
285
 
            AND fixed_upstream IS NOT DISTINCT FROM d.fixed_upstream;
286
 
        IF found THEN
287
 
            RETURN;
288
 
        END IF;
289
 
        -- not there, so try to insert the key
290
 
        -- if someone else inserts the same key concurrently,
291
 
        -- we could get a unique-key failure
292
 
        BEGIN
293
 
            INSERT INTO BugSummary(
294
 
                count, product, productseries, distribution,
295
 
                distroseries, sourcepackagename, viewed_by, tag,
296
 
                status, milestone,
297
 
                importance, has_patch, fixed_upstream)
298
 
            VALUES (
299
 
                d.count, d.product, d.productseries, d.distribution,
300
 
                d.distroseries, d.sourcepackagename, d.viewed_by, d.tag,
301
 
                d.status, d.milestone,
302
 
                d.importance, d.has_patch, d.fixed_upstream);
303
 
            RETURN;
304
 
        EXCEPTION WHEN unique_violation THEN
305
 
            -- do nothing, and loop to try the UPDATE again
306
 
        END;
307
 
    END LOOP;
308
 
END;
309
 
$$;
310
 
 
311
 
COMMENT ON FUNCTION bugsummary_rollup_journal() IS
312
 
'Collate and migrate rows from BugSummaryJournal to BugSummary';
313
 
 
314
 
 
315
 
CREATE OR REPLACE FUNCTION ensure_bugsummary_temp_journal() RETURNS VOID
316
 
LANGUAGE plpgsql VOLATILE AS
317
 
$$
318
 
DECLARE
319
 
BEGIN
320
 
    CREATE TEMPORARY TABLE bugsummary_temp_journal (
321
 
        LIKE bugsummary ) ON COMMIT DROP;
322
 
    ALTER TABLE bugsummary_temp_journal ALTER COLUMN id DROP NOT NULL;
323
 
EXCEPTION
324
 
    WHEN duplicate_table THEN
325
 
        NULL;
326
 
END;
327
 
$$;
328
 
 
329
 
COMMENT ON FUNCTION ensure_bugsummary_temp_journal() IS
330
 
'Create a temporary table bugsummary_temp_journal if it does not exist.';
331
 
 
332
 
 
333
 
CREATE OR REPLACE FUNCTION bug_summary_temp_journal_ins(d bugsummary)
334
 
RETURNS VOID LANGUAGE plpgsql AS
335
 
$$
336
 
BEGIN
337
 
    INSERT INTO BugSummary_Temp_Journal(
338
 
        count, product, productseries, distribution,
339
 
        distroseries, sourcepackagename, viewed_by, tag,
340
 
        status, milestone, importance, has_patch, fixed_upstream)
341
 
    VALUES (
342
 
        d.count, d.product, d.productseries, d.distribution,
343
 
        d.distroseries, d.sourcepackagename, d.viewed_by, d.tag,
344
 
        d.status, d.milestone, d.importance, d.has_patch, d.fixed_upstream);
345
 
    RETURN;
346
 
END;
347
 
$$;
348
 
 
349
 
COMMENT ON FUNCTION bug_summary_temp_journal_ins(bugsummary) IS
350
 
'Insert a BugSummary into the temporary journal';
351
 
 
352
 
 
353
 
DROP FUNCTION bug_summary_temp_journal_dec(bugsummary);
354
 
DROP FUNCTION bug_summary_temp_journal_inc(bugsummary);
355
 
 
356
 
 
357
 
CREATE OR REPLACE FUNCTION bug_summary_flush_temp_journal() RETURNS VOID
358
 
LANGUAGE plpgsql VOLATILE AS
359
 
$$
360
 
DECLARE
361
 
    d bugsummary%ROWTYPE;
362
 
BEGIN
363
 
    -- may get called even though no summaries were made (for simplicity in the
364
 
    -- callers)
365
 
    PERFORM ensure_bugsummary_temp_journal();
366
 
    FOR d IN 
367
 
        SELECT
368
 
            NULL::integer AS id, SUM(count), product, productseries,
369
 
            distribution, distroseries, sourcepackagename,
370
 
            viewed_by, tag, status, milestone,
371
 
            importance, has_patch, fixed_upstream
372
 
        FROM BugSummary_temp_journal
373
 
        GROUP BY
374
 
            product, productseries,
375
 
            distribution, distroseries, sourcepackagename,
376
 
            viewed_by, tag, status, milestone, importance,
377
 
            has_patch, fixed_upstream
378
 
        HAVING SUM(count) <> 0
379
 
    LOOP
380
 
        IF d.count < 0 THEN
381
 
            PERFORM bug_summary_dec(d);
382
 
        ELSE
383
 
            PERFORM bug_summary_inc(d);
384
 
        END IF;
385
 
    END LOOP;
386
 
    TRUNCATE bugsummary_temp_journal;
387
 
END;
388
 
$$;
389
 
 
390
 
COMMENT ON FUNCTION bug_summary_flush_temp_journal() IS
391
 
'flush the temporary bugsummary journal into the bugsummary table';
392
 
 
393
 
 
394
 
CREATE OR REPLACE FUNCTION unsummarise_bug(BUG_ROW bug) RETURNS VOID
395
 
LANGUAGE plpgsql VOLATILE AS
396
 
$$
397
 
DECLARE
398
 
    d bugsummary%ROWTYPE;
399
 
BEGIN
400
 
    PERFORM ensure_bugsummary_temp_journal();
401
 
    FOR d IN SELECT * FROM bugsummary_locations(BUG_ROW) LOOP
402
 
        d.count = -1;
403
 
        PERFORM bug_summary_temp_journal_ins(d);
404
 
    END LOOP;
405
 
END;
406
 
$$;
407
 
 
408
 
CREATE OR REPLACE FUNCTION summarise_bug(BUG_ROW bug) RETURNS VOID
409
 
LANGUAGE plpgsql VOLATILE AS
410
 
$$
411
 
DECLARE
412
 
    d bugsummary%ROWTYPE;
413
 
BEGIN
414
 
    PERFORM ensure_bugsummary_temp_journal();
415
 
    FOR d IN SELECT * FROM bugsummary_locations(BUG_ROW) LOOP
416
 
        d.count = 1;
417
 
        PERFORM bug_summary_temp_journal_ins(d);
418
 
    END LOOP;
419
 
END;
420
 
$$;
421
 
 
422
 
 
423
 
CREATE OR REPLACE FUNCTION bug_maintain_bug_summary() RETURNS TRIGGER
424
 
LANGUAGE plpgsql VOLATILE SECURITY DEFINER SET search_path TO public AS
425
 
$$
426
 
BEGIN
427
 
    -- There is no INSERT logic, as a bug will not have any summary
428
 
    -- information until BugTask rows have been attached.
429
 
    IF TG_OP = 'UPDATE' THEN
430
 
        IF OLD.duplicateof IS DISTINCT FROM NEW.duplicateof
431
 
            OR OLD.private IS DISTINCT FROM NEW.private
432
 
            OR (OLD.latest_patch_uploaded IS NULL)
433
 
                <> (NEW.latest_patch_uploaded IS NULL) THEN
434
 
            PERFORM unsummarise_bug(OLD);
435
 
            PERFORM summarise_bug(NEW);
436
 
        END IF;
437
 
 
438
 
    ELSIF TG_OP = 'DELETE' THEN
439
 
        PERFORM unsummarise_bug(OLD);
440
 
    END IF;
441
 
 
442
 
    PERFORM bug_summary_flush_temp_journal();
443
 
    RETURN NULL; -- Ignored - this is an AFTER trigger
444
 
END;
445
 
$$;
446
 
 
447
 
 
448
 
CREATE OR REPLACE FUNCTION bugtask_maintain_bug_summary() RETURNS TRIGGER
449
 
LANGUAGE plpgsql VOLATILE SECURITY DEFINER SET search_path TO public AS
450
 
$$
451
 
BEGIN
452
 
    -- This trigger only works if we are inserting, updating or deleting
453
 
    -- a single row per statement.
454
 
 
455
 
    -- Unlike bug_maintain_bug_summary, this trigger does not have access
456
 
    -- to the old bug when invoked as an AFTER trigger. To work around this
457
 
    -- we install this trigger as both a BEFORE and an AFTER trigger.
458
 
    IF TG_OP = 'INSERT' THEN
459
 
        IF TG_WHEN = 'BEFORE' THEN
460
 
            PERFORM unsummarise_bug(bug_row(NEW.bug));
461
 
        ELSE
462
 
            PERFORM summarise_bug(bug_row(NEW.bug));
463
 
        END IF;
464
 
        PERFORM bug_summary_flush_temp_journal();
465
 
        RETURN NEW;
466
 
 
467
 
    ELSIF TG_OP = 'DELETE' THEN
468
 
        IF TG_WHEN = 'BEFORE' THEN
469
 
            PERFORM unsummarise_bug(bug_row(OLD.bug));
470
 
        ELSE
471
 
            PERFORM summarise_bug(bug_row(OLD.bug));
472
 
        END IF;
473
 
        PERFORM bug_summary_flush_temp_journal();
474
 
        RETURN OLD;
475
 
 
476
 
    ELSE
477
 
        IF (OLD.product IS DISTINCT FROM NEW.product
478
 
            OR OLD.productseries IS DISTINCT FROM NEW.productseries
479
 
            OR OLD.distribution IS DISTINCT FROM NEW.distribution
480
 
            OR OLD.distroseries IS DISTINCT FROM NEW.distroseries
481
 
            OR OLD.sourcepackagename IS DISTINCT FROM NEW.sourcepackagename
482
 
            OR OLD.status IS DISTINCT FROM NEW.status
483
 
            OR OLD.importance IS DISTINCT FROM NEW.importance
484
 
            OR OLD.bugwatch IS DISTINCT FROM NEW.bugwatch
485
 
            OR OLD.milestone IS DISTINCT FROM NEW.milestone) THEN
486
 
 
487
 
            IF TG_WHEN = 'BEFORE' THEN
488
 
                PERFORM unsummarise_bug(bug_row(OLD.bug));
489
 
                IF OLD.bug <> NEW.bug THEN
490
 
                    PERFORM unsummarise_bug(bug_row(NEW.bug));
491
 
                END IF;
492
 
            ELSE
493
 
                PERFORM summarise_bug(bug_row(OLD.bug));
494
 
                IF OLD.bug <> NEW.bug THEN
495
 
                    PERFORM summarise_bug(bug_row(NEW.bug));
496
 
                END IF;
497
 
            END IF;
498
 
        END IF;
499
 
        PERFORM bug_summary_flush_temp_journal();
500
 
        RETURN NEW;
501
 
    END IF;
502
 
END;
503
 
$$;
504
 
 
505
 
 
506
 
CREATE OR REPLACE FUNCTION bugsummary_locations(BUG_ROW bug)
507
 
RETURNS SETOF bugsummary LANGUAGE plpgsql AS
508
 
$$
509
 
BEGIN
510
 
    IF BUG_ROW.duplicateof IS NOT NULL THEN
511
 
        RETURN;
512
 
    END IF;
513
 
    RETURN QUERY
514
 
        SELECT
515
 
            CAST(NULL AS integer) AS id,
516
 
            CAST(1 AS integer) AS count,
517
 
            product, productseries, distribution, distroseries,
518
 
            sourcepackagename, person AS viewed_by, tag, status, milestone,
519
 
            importance,
520
 
            BUG_ROW.latest_patch_uploaded IS NOT NULL AS has_patch,
521
 
            (EXISTS (
522
 
                SELECT TRUE FROM BugTask AS RBT
523
 
                WHERE
524
 
                    RBT.bug = tasks.bug
525
 
                    -- This would just be 'RBT.id <> tasks.id', except
526
 
                    -- that the records from tasks are summaries and not
527
 
                    -- real bugtasks, and do not have an id.
528
 
                    AND (RBT.product IS DISTINCT FROM tasks.product
529
 
                        OR RBT.productseries
530
 
                            IS DISTINCT FROM tasks.productseries
531
 
                        OR RBT.distribution IS DISTINCT FROM tasks.distribution
532
 
                        OR RBT.distroseries IS DISTINCT FROM tasks.distroseries
533
 
                        OR RBT.sourcepackagename
534
 
                            IS DISTINCT FROM tasks.sourcepackagename)
535
 
                    -- Flagged as INVALID, FIXCOMMITTED or FIXRELEASED
536
 
                    -- via a bugwatch, or FIXCOMMITTED or FIXRELEASED on
537
 
                    -- the product.
538
 
                    AND ((bugwatch IS NOT NULL AND status IN (17, 25, 30))
539
 
                        OR (bugwatch IS NULL AND product IS NOT NULL
540
 
                            AND status IN (25, 30))))
541
 
                )::boolean AS fixed_upstream
542
 
        FROM bugsummary_tasks(BUG_ROW) AS tasks
543
 
        JOIN bugsummary_tags(BUG_ROW) AS bug_tags ON TRUE
544
 
        LEFT OUTER JOIN bugsummary_viewers(BUG_ROW) AS bug_viewers ON TRUE;
545
 
END;
546
 
$$;
547
 
 
548
 
COMMENT ON FUNCTION bugsummary_locations(bug) IS
549
 
'Calculate what BugSummary rows should exist for a given Bug.';
550
 
 
551
 
 
552
 
CREATE OR REPLACE FUNCTION bugsummary_tasks(BUG_ROW bug)
553
 
RETURNS SETOF bugtask LANGUAGE plpgsql STABLE AS
554
 
$$
555
 
DECLARE
556
 
    bt bugtask%ROWTYPE;
557
 
    r record;
558
 
BEGIN
559
 
    bt.bug = BUG_ROW.id;
560
 
 
561
 
    -- One row only for each target permutation - need to ignore other fields
562
 
    -- like date last modified to deal with conjoined masters and multiple
563
 
    -- sourcepackage tasks in a distro.
564
 
    FOR r IN
565
 
        SELECT
566
 
            product, productseries, distribution, distroseries,
567
 
            sourcepackagename, status, milestone, importance, bugwatch
568
 
        FROM BugTask WHERE bug=BUG_ROW.id
569
 
        UNION -- Implicit DISTINCT
570
 
        SELECT
571
 
            product, productseries, distribution, distroseries,
572
 
            NULL, status, milestone, importance, bugwatch
573
 
        FROM BugTask WHERE bug=BUG_ROW.id AND sourcepackagename IS NOT NULL
574
 
    LOOP
575
 
        bt.product = r.product;
576
 
        bt.productseries = r.productseries;
577
 
        bt.distribution = r.distribution;
578
 
        bt.distroseries = r.distroseries;
579
 
        bt.sourcepackagename = r.sourcepackagename;
580
 
        bt.status = r.status;
581
 
        bt.milestone = r.milestone;
582
 
        bt.importance = r.importance;
583
 
        bt.bugwatch = r.bugwatch;
584
 
        RETURN NEXT bt;
585
 
    END LOOP;
586
 
END;
587
 
$$;
588
 
 
589
 
COMMENT ON FUNCTION bugsummary_tasks(bug) IS
590
 
'Return all tasks for the bug + all sourcepackagename tasks again with the sourcepackagename squashed';
591
 
 
592
 
 
593
 
 
594
 
INSERT INTO LaunchpadDatabaseRevision VALUES (2208, 75, 0);