Project

General

Profile

1 5549 aaronmk
/* To get the place trigger, replace taxonconcept with place and remove
2
references to matched_concept_id. */
3 1561 aaronmk
4 5549 aaronmk
----- Functions
5 1558 aaronmk
6 5549 aaronmk
CREATE OR REPLACE FUNCTION taxonconcept_update_ancestors(new taxonconcept, old_parent_id integer DEFAULT NULL::integer)
7
  RETURNS void AS
8 1558 aaronmk
$BODY$
9 5549 aaronmk
DECLARE
10
    -- Use matched_concept_id's ancestors instead if available
11 5554 aaronmk
    parent_id_ taxonconcept.taxonconcept_id%TYPE := COALESCE(
12
        NULLIF(new.matched_concept_id, new.taxonconcept_id), new.parent_id);
13 1558 aaronmk
BEGIN
14 5549 aaronmk
    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 1558 aaronmk
    END IF;
46 1559 aaronmk
47 5549 aaronmk
    /* Note: We don't need an ON DELETE trigger to update the descendants'
48 5551 aaronmk
    ancestors when a node is deleted, because the
49
    taxonconcept_ancestor.ancestor_id foreign key is ON DELETE CASCADE. */
50 5549 aaronmk
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 1559 aaronmk
    INSERT
63 5283 aaronmk
    INTO taxonconcept_ancestor
64
    (taxonconcept_id, ancestor_id)
65
    VALUES (new.taxonconcept_id, new.taxonconcept_id)
66 1559 aaronmk
    ;
67
68 5549 aaronmk
    PERFORM taxonconcept_update_ancestors(new);
69 1559 aaronmk
70 5549 aaronmk
    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 5554 aaronmk
    PERFORM taxonconcept_update_ancestors(new, COALESCE(
81
        NULLIF(old.matched_concept_id, old.taxonconcept_id), old.parent_id));
82 1559 aaronmk
83 1558 aaronmk
    RETURN new;
84
END;
85
$BODY$
86
  LANGUAGE plpgsql VOLATILE
87
  COST 100;
88
89
----- Ancestors table
90
91 5283 aaronmk
CREATE TABLE taxonconcept_ancestor
92 1558 aaronmk
(
93 5283 aaronmk
  taxonconcept_id integer NOT NULL,
94 1558 aaronmk
  ancestor_id integer NOT NULL,
95 5283 aaronmk
  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 1558 aaronmk
      ON UPDATE CASCADE ON DELETE CASCADE,
99 5283 aaronmk
  CONSTRAINT taxonconcept_ancestor_taxonconcept_id_fkey FOREIGN KEY (taxonconcept_id)
100
      REFERENCES taxonconcept (taxonconcept_id) MATCH SIMPLE
101 1558 aaronmk
      ON UPDATE CASCADE ON DELETE CASCADE
102
)
103
WITH (
104
  OIDS=FALSE
105
);
106 5549 aaronmk
COMMENT ON TABLE taxonconcept_ancestor
107
  IS 'Stores the accepted ancestors of a taxonconcept. Auto-populated, so should not be manually modified.';
108 1558 aaronmk
109 5549 aaronmk
CREATE INDEX taxonconcept_ancestor_descendants
110
  ON taxonconcept_ancestor
111
  USING btree
112
  (ancestor_id , taxonconcept_id );
113 1558 aaronmk
114 5549 aaronmk
----- Triggers
115
116
CREATE TRIGGER taxonconcept_update_ancestors_on_insert
117
  AFTER INSERT
118 5283 aaronmk
  ON taxonconcept
119 1558 aaronmk
  FOR EACH ROW
120 5549 aaronmk
  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();