Revision 5549
Added by Aaron Marcuse-Kubitza about 12 years ago
schemas/tree_cross-links.sql | ||
---|---|---|
1 |
/* To get the place trigger, just search and replace taxonconcept with place. */ |
|
1 |
/* To get the place trigger, replace taxonconcept with place and remove |
|
2 |
references to matched_concept_id. */ |
|
2 | 3 |
|
3 |
----- Trigger function
|
|
4 |
----- Functions
|
|
4 | 5 |
|
5 |
-- Function: taxonconcept_update_ancestors() |
|
6 |
-- Function: taxonconcept_update_ancestors(taxonconcept, integer)
|
|
6 | 7 |
|
7 |
-- DROP FUNCTION taxonconcept_update_ancestors(); |
|
8 |
-- DROP FUNCTION taxonconcept_update_ancestors(taxonconcept, integer);
|
|
8 | 9 |
|
9 |
CREATE OR REPLACE FUNCTION taxonconcept_update_ancestors() |
|
10 |
RETURNS trigger AS
|
|
10 |
CREATE OR REPLACE FUNCTION taxonconcept_update_ancestors(new taxonconcept, old_parent_id integer DEFAULT NULL::integer)
|
|
11 |
RETURNS void AS
|
|
11 | 12 |
$BODY$ |
13 |
DECLARE |
|
14 |
-- Use matched_concept_id's ancestors instead if available |
|
15 |
parent_id_ taxonconcept.taxonconcept_id%TYPE := |
|
16 |
COALESCE(new.matched_concept_id, new.parent_id); |
|
12 | 17 |
BEGIN |
13 |
-- Delete existing ancestors |
|
14 |
DELETE FROM taxonconcept_ancestor |
|
15 |
WHERE taxonconcept_id = new.taxonconcept_id; |
|
16 |
|
|
17 |
IF new.parent_id IS NOT NULL THEN |
|
18 |
-- Copy parent's ancestors to this node's ancestors |
|
19 |
INSERT |
|
20 |
INTO taxonconcept_ancestor |
|
21 |
(taxonconcept_id, ancestor_id) |
|
22 |
SELECT |
|
23 |
new.taxonconcept_id, ancestor_id |
|
24 |
FROM taxonconcept_ancestor |
|
25 |
WHERE taxonconcept_id = new.parent_id |
|
26 |
; |
|
18 |
IF parent_id_ IS DISTINCT FROM old_parent_id THEN |
|
19 |
DECLARE |
|
20 |
-- These include the parent itself |
|
21 |
old_ancestors integer[] := ( |
|
22 |
SELECT array_agg(ancestor_id) FROM taxonconcept_ancestor |
|
23 |
WHERE taxonconcept_id = old_parent_id |
|
24 |
); |
|
25 |
new_ancestors integer[] := ( |
|
26 |
SELECT array_agg(ancestor_id) FROM taxonconcept_ancestor |
|
27 |
WHERE taxonconcept_id = parent_id_ |
|
28 |
); |
|
29 |
descendant_id integer; |
|
30 |
BEGIN |
|
31 |
FOR descendant_id IN -- also includes self |
|
32 |
SELECT taxonconcept_id |
|
33 |
FROM taxonconcept_ancestor |
|
34 |
WHERE ancestor_id = new.taxonconcept_id |
|
35 |
LOOP |
|
36 |
-- Delete old parent's ancestors |
|
37 |
DELETE FROM taxonconcept_ancestor |
|
38 |
WHERE taxonconcept_id = descendant_id |
|
39 |
AND ancestor_id = ANY (old_ancestors) |
|
40 |
; |
|
41 |
|
|
42 |
-- Add new parent's ancestors |
|
43 |
INSERT INTO taxonconcept_ancestor |
|
44 |
(taxonconcept_id, ancestor_id) |
|
45 |
SELECT descendant_id, unnest(new_ancestors) |
|
46 |
; |
|
47 |
END LOOP; |
|
48 |
END; |
|
27 | 49 |
END IF; |
28 | 50 |
|
29 |
-- Add "ancestor" for this node |
|
30 |
/* This is useful for queries, because you don't have to separately test if |
|
31 |
the leaf node is the one you're looking for, in addition to that leaf node's |
|
32 |
ancestors. */ |
|
51 |
/* Note: We don't need an ON DELETE trigger to update the descendants' |
|
52 |
ancestors when a node is deleted, because the taxonconcept.parent_id foreign |
|
53 |
key is ON DELETE CASCADE, which just removes all the descendants anyway. */ |
|
54 |
END; |
|
55 |
$BODY$ |
|
56 |
LANGUAGE plpgsql VOLATILE |
|
57 |
COST 100; |
|
58 |
ALTER FUNCTION taxonconcept_update_ancestors(taxonconcept, integer) |
|
59 |
OWNER TO bien; |
|
60 |
|
|
61 |
-- Function: taxonconcept_update_ancestors_on_insert() |
|
62 |
|
|
63 |
-- DROP FUNCTION taxonconcept_update_ancestors_on_insert(); |
|
64 |
|
|
65 |
CREATE OR REPLACE FUNCTION taxonconcept_update_ancestors_on_insert() |
|
66 |
RETURNS trigger AS |
|
67 |
$BODY$ |
|
68 |
BEGIN |
|
69 |
/* Add "ancestor" for this node. This is useful for queries, because you |
|
70 |
don't have to separately test if the leaf node is the one you're looking |
|
71 |
for, in addition to that leaf node's ancestors. */ |
|
33 | 72 |
INSERT |
34 | 73 |
INTO taxonconcept_ancestor |
35 | 74 |
(taxonconcept_id, ancestor_id) |
36 | 75 |
VALUES (new.taxonconcept_id, new.taxonconcept_id) |
37 | 76 |
; |
38 | 77 |
|
39 |
-- Tell immediate children to update their ancestors lists, which will |
|
40 |
-- recursively tell all descendants |
|
41 |
UPDATE taxonconcept |
|
42 |
SET taxonconcept_id = taxonconcept_id -- need at least one SET statement |
|
43 |
-- Add COALESCE() to enable using taxonconcept_unique index for lookup |
|
44 |
WHERE COALESCE(parent_id, 2147483647) = new.taxonconcept_id |
|
45 |
AND taxonconcept_id != new.taxonconcept_id -- avoid infinite recursion |
|
46 |
; |
|
78 |
PERFORM taxonconcept_update_ancestors(new); |
|
47 | 79 |
|
48 |
/* Note: We don't need an ON DELETE trigger to update the descendants' |
|
49 |
ancestors when a node is deleted, because the taxonconcept.parent_id foreign |
|
50 |
key is ON DELETE CASCADE, which just removes all the descendants anyway. */ |
|
80 |
RETURN new; |
|
81 |
END; |
|
82 |
$BODY$ |
|
83 |
LANGUAGE plpgsql VOLATILE |
|
84 |
COST 100; |
|
85 |
ALTER FUNCTION taxonconcept_update_ancestors_on_insert() |
|
86 |
OWNER TO bien; |
|
87 |
|
|
88 |
-- Function: taxonconcept_update_ancestors_on_update() |
|
89 |
|
|
90 |
-- DROP FUNCTION taxonconcept_update_ancestors_on_update(); |
|
91 |
|
|
92 |
CREATE OR REPLACE FUNCTION taxonconcept_update_ancestors_on_update() |
|
93 |
RETURNS trigger AS |
|
94 |
$BODY$ |
|
95 |
BEGIN |
|
96 |
PERFORM taxonconcept_update_ancestors(new, |
|
97 |
COALESCE(old.matched_concept_id, old.parent_id)); |
|
51 | 98 |
|
52 | 99 |
RETURN new; |
53 | 100 |
END; |
54 | 101 |
$BODY$ |
55 | 102 |
LANGUAGE plpgsql VOLATILE |
56 | 103 |
COST 100; |
57 |
ALTER FUNCTION taxonconcept_update_ancestors() |
|
104 |
ALTER FUNCTION taxonconcept_update_ancestors_on_update()
|
|
58 | 105 |
OWNER TO bien; |
59 | 106 |
|
60 | 107 |
----- Ancestors table |
... | ... | |
80 | 127 |
); |
81 | 128 |
ALTER TABLE taxonconcept_ancestor |
82 | 129 |
OWNER TO bien; |
130 |
COMMENT ON TABLE taxonconcept_ancestor |
|
131 |
IS 'Stores the accepted ancestors of a taxonconcept. Auto-populated, so should not be manually modified.'; |
|
83 | 132 |
|
84 |
----- Trigger
|
|
133 |
-- Index: taxonconcept_ancestor_descendants
|
|
85 | 134 |
|
86 |
-- Trigger: taxonconcept_update_ancestors on taxonconcept
|
|
135 |
-- DROP INDEX taxonconcept_ancestor_descendants;
|
|
87 | 136 |
|
88 |
-- DROP TRIGGER taxonconcept_update_ancestors ON taxonconcept; |
|
137 |
CREATE INDEX taxonconcept_ancestor_descendants |
|
138 |
ON taxonconcept_ancestor |
|
139 |
USING btree |
|
140 |
(ancestor_id , taxonconcept_id ); |
|
89 | 141 |
|
90 |
CREATE TRIGGER taxonconcept_update_ancestors |
|
91 |
AFTER INSERT OR UPDATE |
|
142 |
|
|
143 |
----- Triggers |
|
144 |
|
|
145 |
-- Trigger: taxonconcept_update_ancestors_on_insert on taxonconcept |
|
146 |
|
|
147 |
-- DROP TRIGGER taxonconcept_update_ancestors_on_insert ON taxonconcept; |
|
148 |
|
|
149 |
CREATE TRIGGER taxonconcept_update_ancestors_on_insert |
|
150 |
AFTER INSERT |
|
92 | 151 |
ON taxonconcept |
93 | 152 |
FOR EACH ROW |
94 |
EXECUTE PROCEDURE taxonconcept_update_ancestors(); |
|
153 |
EXECUTE PROCEDURE taxonconcept_update_ancestors_on_insert(); |
|
154 |
|
|
155 |
-- Trigger: taxonconcept_update_ancestors_on_update on taxonconcept |
|
156 |
|
|
157 |
-- DROP TRIGGER taxonconcept_update_ancestors_on_update ON taxonconcept; |
|
158 |
|
|
159 |
CREATE TRIGGER taxonconcept_update_ancestors_on_update |
|
160 |
AFTER UPDATE |
|
161 |
ON taxonconcept |
|
162 |
FOR EACH ROW |
|
163 |
EXECUTE PROCEDURE taxonconcept_update_ancestors_on_update(); |
Also available in: Unified diff
schemas/tree_cross-links.sql: Updated for new taxonconcept_update_ancestors() trigger