Protect URI reingest from failure due to malformed XML
[Evergreen.git] / Open-ILS / src / sql / Pg / upgrade / 0559.schema.biblio.extract_located_uris.sql
1 -- Evergreen DB patch 0559.schema.biblio.extract_located_uris.sql
2 --
3 -- * Add a stored procedure to reingest problematic URIs
4 -- * Avoid duplicate row issues in biblio.extract_located_uris
5 -- * Fix LP 797304 and 797307 - asset.uri parsing bugs
6 --
7 BEGIN;
8
9
10 -- check whether patch can be applied
11 SELECT evergreen.upgrade_deps_block_check('0559', :eg_version);
12
13 -- FIXME: add/check SQL statements to perform the upgrade
14 CREATE OR REPLACE FUNCTION biblio.extract_located_uris( bib_id BIGINT, marcxml TEXT, editor_id INT ) RETURNS VOID AS $func$
15 DECLARE
16     uris            TEXT[];
17     uri_xml         TEXT;
18     uri_label       TEXT;
19     uri_href        TEXT;
20     uri_use         TEXT;
21     uri_owner_list  TEXT[];
22     uri_owner       TEXT;
23     uri_owner_id    INT;
24     uri_id          INT;
25     uri_cn_id       INT;
26     uri_map_id      INT;
27 BEGIN
28
29     -- Clear any URI mappings and call numbers for this bib.
30     -- This leads to acn / auricnm inflation, but also enables
31     -- old acn/auricnm's to go away and for bibs to be deleted.
32     FOR uri_cn_id IN SELECT id FROM asset.call_number WHERE record = bib_id AND label = '##URI##' AND NOT deleted LOOP
33         DELETE FROM asset.uri_call_number_map WHERE call_number = uri_cn_id;
34         DELETE FROM asset.call_number WHERE id = uri_cn_id;
35     END LOOP;
36
37     uris := oils_xpath('//*[@tag="856" and (@ind1="4" or @ind1="1") and (@ind2="0" or @ind2="1")]',marcxml);
38     IF ARRAY_UPPER(uris,1) > 0 THEN
39         FOR i IN 1 .. ARRAY_UPPER(uris, 1) LOOP
40             -- First we pull info out of the 856
41             uri_xml     := uris[i];
42
43             uri_href    := (oils_xpath('//*[@code="u"]/text()',uri_xml))[1];
44             uri_label   := (oils_xpath('//*[@code="y"]/text()|//*[@code="3"]/text()',uri_xml))[1];
45             uri_use     := (oils_xpath('//*[@code="z"]/text()|//*[@code="2"]/text()|//*[@code="n"]/text()',uri_xml))[1];
46
47             IF uri_label IS NULL THEN
48                 uri_label := uri_href;
49             END IF;
50             CONTINUE WHEN uri_href IS NULL;
51
52             -- Get the distinct list of libraries wanting to use 
53             SELECT  ARRAY_ACCUM(
54                         DISTINCT REGEXP_REPLACE(
55                             x,
56                             $re$^.*?\((\w+)\).*$$re$,
57                             E'\\1'
58                         )
59                     ) INTO uri_owner_list
60               FROM  UNNEST(
61                         oils_xpath(
62                             '//*[@code="9"]/text()|//*[@code="w"]/text()|//*[@code="n"]/text()',
63                             uri_xml
64                         )
65                     )x;
66
67             IF ARRAY_UPPER(uri_owner_list,1) > 0 THEN
68
69                 -- look for a matching uri
70                 IF uri_use IS NULL THEN
71                     SELECT id INTO uri_id
72                         FROM asset.uri
73                         WHERE label = uri_label AND href = uri_href AND use_restriction IS NULL AND active
74                         ORDER BY id LIMIT 1;
75                     IF NOT FOUND THEN -- create one
76                         INSERT INTO asset.uri (label, href, use_restriction) VALUES (uri_label, uri_href, uri_use);
77                         SELECT id INTO uri_id
78                             FROM asset.uri
79                             WHERE label = uri_label AND href = uri_href AND use_restriction IS NULL AND active;
80                     END IF;
81                 ELSE
82                     SELECT id INTO uri_id
83                         FROM asset.uri
84                         WHERE label = uri_label AND href = uri_href AND use_restriction = uri_use AND active
85                         ORDER BY id LIMIT 1;
86                     IF NOT FOUND THEN -- create one
87                         INSERT INTO asset.uri (label, href, use_restriction) VALUES (uri_label, uri_href, uri_use);
88                         SELECT id INTO uri_id
89                             FROM asset.uri
90                             WHERE label = uri_label AND href = uri_href AND use_restriction = uri_use AND active;
91                     END IF;
92                 END IF;
93
94                 FOR j IN 1 .. ARRAY_UPPER(uri_owner_list, 1) LOOP
95                     uri_owner := uri_owner_list[j];
96
97                     SELECT id INTO uri_owner_id FROM actor.org_unit WHERE shortname = uri_owner;
98                     CONTINUE WHEN NOT FOUND;
99
100                     -- we need a call number to link through
101                     SELECT id INTO uri_cn_id FROM asset.call_number WHERE owning_lib = uri_owner_id AND record = bib_id AND label = '##URI##' AND NOT deleted;
102                     IF NOT FOUND THEN
103                         INSERT INTO asset.call_number (owning_lib, record, create_date, edit_date, creator, editor, label)
104                             VALUES (uri_owner_id, bib_id, 'now', 'now', editor_id, editor_id, '##URI##');
105                         SELECT id INTO uri_cn_id FROM asset.call_number WHERE owning_lib = uri_owner_id AND record = bib_id AND label = '##URI##' AND NOT deleted;
106                     END IF;
107
108                     -- now, link them if they're not already
109                     SELECT id INTO uri_map_id FROM asset.uri_call_number_map WHERE call_number = uri_cn_id AND uri = uri_id;
110                     IF NOT FOUND THEN
111                         INSERT INTO asset.uri_call_number_map (call_number, uri) VALUES (uri_cn_id, uri_id);
112                     END IF;
113
114                 END LOOP;
115
116             END IF;
117
118         END LOOP;
119     END IF;
120
121     RETURN;
122 END;
123 $func$ LANGUAGE PLPGSQL;
124
125 CREATE OR REPLACE FUNCTION biblio.reingest_uris() RETURNS VOID AS $func$
126 DECLARE
127     rec_id BIGINT;
128 BEGIN
129     -- Get the distinct set of record IDs that need to be reingested
130     -- (assuming that href = label is a reasonable red flag)
131     FOR rec_id IN SELECT rec_uris.id FROM (
132         SELECT acn.record AS id
133             FROM asset.call_number acn
134                 INNER JOIN asset.uri_call_number_map auricnm ON auricnm.call_number = acn.id
135                 INNER JOIN asset.uri auri ON auri.id = auricnm.uri
136                 INNER JOIN biblio.record_entry bre ON acn.record = bre.id
137             WHERE auri.href = auri.label
138                 AND xml_is_well_formed(bre.marc)
139             GROUP BY acn.record
140             ORDER BY acn.record
141         ) AS rec_uris
142     LOOP
143         -- Reingest the offending records
144         PERFORM biblio.extract_located_uris(rec_id, bre.marc, 1)
145             FROM biblio.record_entry bre
146             WHERE bre.id = rec_id;
147     END LOOP;
148 END;
149 $func$ LANGUAGE PLPGSQL;
150
151 -- Kick off the reingest; this may take a while
152 SELECT biblio.reingest_uris();
153
154
155 COMMIT;