Project

General

Profile

1
/* To get the place trigger, replace taxonconcept with place and remove
2
references to matched_concept_id. */
3

    
4
----- Functions
5

    
6
CREATE OR REPLACE FUNCTION taxonconcept_update_ancestors(new taxonconcept, old_parent_id integer DEFAULT NULL::integer)
7
  RETURNS void AS
8
$BODY$
9
DECLARE
10
    -- Use matched_concept_id's ancestors instead if available
11
    parent_id_ taxonconcept.taxonconcept_id%TYPE := COALESCE(
12
        NULLIF(new.matched_concept_id, new.taxonconcept_id), new.parent_id);
13
BEGIN
14
    IF parent_id_ IS DISTINCT FROM old_parent_id THEN
15
        DECLARE
16
            -- These include the parent itself
17
            old_ancestors integer[] := (
18
                SELECT array_agg(ancestor_id) FROM taxonconcept_ancestor
19
                WHERE taxonconcept_id = old_parent_id
20
            );
21
            new_ancestors integer[] := (
22
                SELECT array_agg(ancestor_id) FROM taxonconcept_ancestor
23
                WHERE taxonconcept_id = parent_id_
24
            );
25
            descendant_id integer;
26
        BEGIN
27
            FOR descendant_id IN -- also includes self
28
                SELECT taxonconcept_id
29
                FROM taxonconcept_ancestor
30
                WHERE ancestor_id = new.taxonconcept_id
31
            LOOP
32
                -- Delete old parent's ancestors
33
                DELETE FROM taxonconcept_ancestor
34
                WHERE taxonconcept_id = descendant_id
35
                AND ancestor_id = ANY (old_ancestors)
36
                ;
37
                
38
                -- Add new parent's ancestors
39
                INSERT INTO taxonconcept_ancestor
40
                (taxonconcept_id, ancestor_id)
41
                SELECT descendant_id, unnest(new_ancestors)
42
                ;
43
            END LOOP;
44
        END;
45
    END IF;
46
    
47
    /* Note: We don't need an ON DELETE trigger to update the descendants'
48
    ancestors when a node is deleted, because the
49
    taxonconcept_ancestor.ancestor_id foreign key is ON DELETE CASCADE. */
50
END;
51
$BODY$
52
  LANGUAGE plpgsql VOLATILE
53
  COST 100;
54

    
55
CREATE OR REPLACE FUNCTION taxonconcept_update_ancestors_on_insert()
56
  RETURNS trigger AS
57
$BODY$
58
BEGIN
59
    /* Add "ancestor" for this node. This is useful for queries, because you
60
    don't have to separately test if the leaf node is the one you're looking
61
    for, in addition to that leaf node's ancestors. */
62
    INSERT
63
    INTO taxonconcept_ancestor
64
    (taxonconcept_id, ancestor_id)
65
    VALUES (new.taxonconcept_id, new.taxonconcept_id)
66
    ;
67
    
68
    PERFORM taxonconcept_update_ancestors(new);
69
    
70
    RETURN new;
71
END;
72
$BODY$
73
  LANGUAGE plpgsql VOLATILE
74
  COST 100;
75

    
76
CREATE OR REPLACE FUNCTION taxonconcept_update_ancestors_on_update()
77
  RETURNS trigger AS
78
$BODY$
79
BEGIN
80
    PERFORM taxonconcept_update_ancestors(new, COALESCE(
81
        NULLIF(old.matched_concept_id, old.taxonconcept_id), old.parent_id));
82
    
83
    RETURN new;
84
END;
85
$BODY$
86
  LANGUAGE plpgsql VOLATILE
87
  COST 100;
88

    
89
----- Ancestors table
90

    
91
CREATE TABLE taxonconcept_ancestor
92
(
93
  taxonconcept_id integer NOT NULL,
94
  ancestor_id integer NOT NULL,
95
  CONSTRAINT taxonconcept_ancestor_pkey PRIMARY KEY (taxonconcept_id , ancestor_id ),
96
  CONSTRAINT taxonconcept_ancestor_ancestor_id_fkey FOREIGN KEY (ancestor_id)
97
      REFERENCES taxonconcept (taxonconcept_id) MATCH SIMPLE
98
      ON UPDATE CASCADE ON DELETE CASCADE,
99
  CONSTRAINT taxonconcept_ancestor_taxonconcept_id_fkey FOREIGN KEY (taxonconcept_id)
100
      REFERENCES taxonconcept (taxonconcept_id) MATCH SIMPLE
101
      ON UPDATE CASCADE ON DELETE CASCADE
102
)
103
WITH (
104
  OIDS=FALSE
105
);
106
COMMENT ON TABLE taxonconcept_ancestor
107
  IS 'Stores the accepted ancestors of a taxonconcept. Auto-populated, so should not be manually modified.';
108

    
109
CREATE INDEX taxonconcept_ancestor_descendants
110
  ON taxonconcept_ancestor
111
  USING btree
112
  (ancestor_id , taxonconcept_id );
113

    
114
----- Triggers
115

    
116
CREATE TRIGGER taxonconcept_update_ancestors_on_insert
117
  AFTER INSERT
118
  ON taxonconcept
119
  FOR EACH ROW
120
  EXECUTE PROCEDURE taxonconcept_update_ancestors_on_insert();
121

    
122
CREATE TRIGGER taxonconcept_update_ancestors_on_update
123
  AFTER UPDATE
124
  ON taxonconcept
125
  FOR EACH ROW
126
  EXECUTE PROCEDURE taxonconcept_update_ancestors_on_update();
(10-10/20)