]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/sql/Pg/upgrade/0731.schema.vandelay_item_overlay.sql
Break up expensive queries, match index to quals
[working/Evergreen.git] / Open-ILS / src / sql / Pg / upgrade / 0731.schema.vandelay_item_overlay.sql
1 -- 0731.schema.vandelay_item_overlay.sql
2 BEGIN;
3
4 SELECT evergreen.upgrade_deps_block_check('0731', :eg_version);
5
6 ALTER TABLE vandelay.import_item_attr_definition 
7     ADD COLUMN internal_id TEXT; 
8
9 ALTER TABLE vandelay.import_item 
10     ADD COLUMN internal_id BIGINT;
11
12 INSERT INTO permission.perm_list ( id, code, description ) VALUES
13 ( 536, 'IMPORT_OVERLAY_COPY', oils_i18n_gettext( 536,
14     'Allows a user to overlay copy data in MARC import', 'ppl', 'description'));
15
16 CREATE OR REPLACE FUNCTION vandelay.ingest_bib_items ( ) RETURNS TRIGGER AS $func$
17 DECLARE
18     attr_def    BIGINT;
19     item_data   vandelay.import_item%ROWTYPE;
20 BEGIN
21
22     IF TG_OP IN ('INSERT','UPDATE') AND NEW.imported_as IS NOT NULL THEN
23         RETURN NEW;
24     END IF;
25
26     SELECT item_attr_def INTO attr_def FROM vandelay.bib_queue WHERE id = NEW.queue;
27
28     FOR item_data IN SELECT * FROM vandelay.ingest_items( NEW.id::BIGINT, attr_def ) LOOP
29         INSERT INTO vandelay.import_item (
30             record,
31             definition,
32             owning_lib,
33             circ_lib,
34             call_number,
35             copy_number,
36             status,
37             location,
38             circulate,
39             deposit,
40             deposit_amount,
41             ref,
42             holdable,
43             price,
44             barcode,
45             circ_modifier,
46             circ_as_type,
47             alert_message,
48             pub_note,
49             priv_note,
50             internal_id,
51             opac_visible,
52             import_error,
53             error_detail
54         ) VALUES (
55             NEW.id,
56             item_data.definition,
57             item_data.owning_lib,
58             item_data.circ_lib,
59             item_data.call_number,
60             item_data.copy_number,
61             item_data.status,
62             item_data.location,
63             item_data.circulate,
64             item_data.deposit,
65             item_data.deposit_amount,
66             item_data.ref,
67             item_data.holdable,
68             item_data.price,
69             item_data.barcode,
70             item_data.circ_modifier,
71             item_data.circ_as_type,
72             item_data.alert_message,
73             item_data.pub_note,
74             item_data.priv_note,
75             item_data.internal_id,
76             item_data.opac_visible,
77             item_data.import_error,
78             item_data.error_detail
79         );
80     END LOOP;
81
82     RETURN NULL;
83 END;
84 $func$ LANGUAGE PLPGSQL;
85
86
87 CREATE OR REPLACE FUNCTION vandelay.ingest_items ( import_id BIGINT, attr_def_id BIGINT ) RETURNS SETOF vandelay.import_item AS $$
88 DECLARE
89
90     owning_lib      TEXT;
91     circ_lib        TEXT;
92     call_number     TEXT;
93     copy_number     TEXT;
94     status          TEXT;
95     location        TEXT;
96     circulate       TEXT;
97     deposit         TEXT;
98     deposit_amount  TEXT;
99     ref             TEXT;
100     holdable        TEXT;
101     price           TEXT;
102     barcode         TEXT;
103     circ_modifier   TEXT;
104     circ_as_type    TEXT;
105     alert_message   TEXT;
106     opac_visible    TEXT;
107     pub_note        TEXT;
108     priv_note       TEXT;
109     internal_id     TEXT;
110
111     attr_def        RECORD;
112     tmp_attr_set    RECORD;
113     attr_set        vandelay.import_item%ROWTYPE;
114
115     xpath           TEXT;
116     tmp_str         TEXT;
117
118 BEGIN
119
120     SELECT * INTO attr_def FROM vandelay.import_item_attr_definition WHERE id = attr_def_id;
121
122     IF FOUND THEN
123
124         attr_set.definition := attr_def.id;
125
126         -- Build the combined XPath
127
128         owning_lib :=
129             CASE
130                 WHEN attr_def.owning_lib IS NULL THEN 'null()'
131                 WHEN LENGTH( attr_def.owning_lib ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.owning_lib || '"]'
132                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.owning_lib
133             END;
134
135         circ_lib :=
136             CASE
137                 WHEN attr_def.circ_lib IS NULL THEN 'null()'
138                 WHEN LENGTH( attr_def.circ_lib ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circ_lib || '"]'
139                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circ_lib
140             END;
141
142         call_number :=
143             CASE
144                 WHEN attr_def.call_number IS NULL THEN 'null()'
145                 WHEN LENGTH( attr_def.call_number ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.call_number || '"]'
146                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.call_number
147             END;
148
149         copy_number :=
150             CASE
151                 WHEN attr_def.copy_number IS NULL THEN 'null()'
152                 WHEN LENGTH( attr_def.copy_number ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.copy_number || '"]'
153                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.copy_number
154             END;
155
156         status :=
157             CASE
158                 WHEN attr_def.status IS NULL THEN 'null()'
159                 WHEN LENGTH( attr_def.status ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.status || '"]'
160                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.status
161             END;
162
163         location :=
164             CASE
165                 WHEN attr_def.location IS NULL THEN 'null()'
166                 WHEN LENGTH( attr_def.location ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.location || '"]'
167                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.location
168             END;
169
170         circulate :=
171             CASE
172                 WHEN attr_def.circulate IS NULL THEN 'null()'
173                 WHEN LENGTH( attr_def.circulate ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circulate || '"]'
174                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circulate
175             END;
176
177         deposit :=
178             CASE
179                 WHEN attr_def.deposit IS NULL THEN 'null()'
180                 WHEN LENGTH( attr_def.deposit ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.deposit || '"]'
181                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.deposit
182             END;
183
184         deposit_amount :=
185             CASE
186                 WHEN attr_def.deposit_amount IS NULL THEN 'null()'
187                 WHEN LENGTH( attr_def.deposit_amount ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.deposit_amount || '"]'
188                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.deposit_amount
189             END;
190
191         ref :=
192             CASE
193                 WHEN attr_def.ref IS NULL THEN 'null()'
194                 WHEN LENGTH( attr_def.ref ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.ref || '"]'
195                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.ref
196             END;
197
198         holdable :=
199             CASE
200                 WHEN attr_def.holdable IS NULL THEN 'null()'
201                 WHEN LENGTH( attr_def.holdable ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.holdable || '"]'
202                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.holdable
203             END;
204
205         price :=
206             CASE
207                 WHEN attr_def.price IS NULL THEN 'null()'
208                 WHEN LENGTH( attr_def.price ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.price || '"]'
209                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.price
210             END;
211
212         barcode :=
213             CASE
214                 WHEN attr_def.barcode IS NULL THEN 'null()'
215                 WHEN LENGTH( attr_def.barcode ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.barcode || '"]'
216                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.barcode
217             END;
218
219         circ_modifier :=
220             CASE
221                 WHEN attr_def.circ_modifier IS NULL THEN 'null()'
222                 WHEN LENGTH( attr_def.circ_modifier ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circ_modifier || '"]'
223                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circ_modifier
224             END;
225
226         circ_as_type :=
227             CASE
228                 WHEN attr_def.circ_as_type IS NULL THEN 'null()'
229                 WHEN LENGTH( attr_def.circ_as_type ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circ_as_type || '"]'
230                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circ_as_type
231             END;
232
233         alert_message :=
234             CASE
235                 WHEN attr_def.alert_message IS NULL THEN 'null()'
236                 WHEN LENGTH( attr_def.alert_message ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.alert_message || '"]'
237                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.alert_message
238             END;
239
240         opac_visible :=
241             CASE
242                 WHEN attr_def.opac_visible IS NULL THEN 'null()'
243                 WHEN LENGTH( attr_def.opac_visible ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.opac_visible || '"]'
244                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.opac_visible
245             END;
246
247         pub_note :=
248             CASE
249                 WHEN attr_def.pub_note IS NULL THEN 'null()'
250                 WHEN LENGTH( attr_def.pub_note ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.pub_note || '"]'
251                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.pub_note
252             END;
253         priv_note :=
254             CASE
255                 WHEN attr_def.priv_note IS NULL THEN 'null()'
256                 WHEN LENGTH( attr_def.priv_note ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.priv_note || '"]'
257                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.priv_note
258             END;
259
260         internal_id :=
261             CASE
262                 WHEN attr_def.internal_id IS NULL THEN 'null()'
263                 WHEN LENGTH( attr_def.internal_id ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.internal_id || '"]'
264                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.internal_id
265             END;
266
267
268
269         xpath :=
270             owning_lib      || '|' ||
271             circ_lib        || '|' ||
272             call_number     || '|' ||
273             copy_number     || '|' ||
274             status          || '|' ||
275             location        || '|' ||
276             circulate       || '|' ||
277             deposit         || '|' ||
278             deposit_amount  || '|' ||
279             ref             || '|' ||
280             holdable        || '|' ||
281             price           || '|' ||
282             barcode         || '|' ||
283             circ_modifier   || '|' ||
284             circ_as_type    || '|' ||
285             alert_message   || '|' ||
286             pub_note        || '|' ||
287             priv_note       || '|' ||
288             internal_id     || '|' ||
289             opac_visible;
290
291         FOR tmp_attr_set IN
292                 SELECT  *
293                   FROM  oils_xpath_table( 'id', 'marc', 'vandelay.queued_bib_record', xpath, 'id = ' || import_id )
294                             AS t( id INT, ol TEXT, clib TEXT, cn TEXT, cnum TEXT, cs TEXT, cl TEXT, circ TEXT,
295                                   dep TEXT, dep_amount TEXT, r TEXT, hold TEXT, pr TEXT, bc TEXT, circ_mod TEXT,
296                                   circ_as TEXT, amessage TEXT, note TEXT, pnote TEXT, internal_id TEXT, opac_vis TEXT )
297         LOOP
298
299             attr_set.import_error := NULL;
300             attr_set.error_detail := NULL;
301             attr_set.deposit_amount := NULL;
302             attr_set.copy_number := NULL;
303             attr_set.price := NULL;
304
305             IF tmp_attr_set.pr != '' THEN
306                 tmp_str = REGEXP_REPLACE(tmp_attr_set.pr, E'[^0-9\\.]', '', 'g');
307                 IF tmp_str = '' THEN 
308                     attr_set.import_error := 'import.item.invalid.price';
309                     attr_set.error_detail := tmp_attr_set.pr; -- original value
310                     RETURN NEXT attr_set; CONTINUE; 
311                 END IF;
312                 attr_set.price := tmp_str::NUMERIC(8,2); 
313             END IF;
314
315             IF tmp_attr_set.dep_amount != '' THEN
316                 tmp_str = REGEXP_REPLACE(tmp_attr_set.dep_amount, E'[^0-9\\.]', '', 'g');
317                 IF tmp_str = '' THEN 
318                     attr_set.import_error := 'import.item.invalid.deposit_amount';
319                     attr_set.error_detail := tmp_attr_set.dep_amount; 
320                     RETURN NEXT attr_set; CONTINUE; 
321                 END IF;
322                 attr_set.deposit_amount := tmp_str::NUMERIC(8,2); 
323             END IF;
324
325             IF tmp_attr_set.cnum != '' THEN
326                 tmp_str = REGEXP_REPLACE(tmp_attr_set.cnum, E'[^0-9]', '', 'g');
327                 IF tmp_str = '' THEN 
328                     attr_set.import_error := 'import.item.invalid.copy_number';
329                     attr_set.error_detail := tmp_attr_set.cnum; 
330                     RETURN NEXT attr_set; CONTINUE; 
331                 END IF;
332                 attr_set.copy_number := tmp_str::INT; 
333             END IF;
334
335             IF tmp_attr_set.ol != '' THEN
336                 SELECT id INTO attr_set.owning_lib FROM actor.org_unit WHERE shortname = UPPER(tmp_attr_set.ol); -- INT
337                 IF NOT FOUND THEN
338                     attr_set.import_error := 'import.item.invalid.owning_lib';
339                     attr_set.error_detail := tmp_attr_set.ol;
340                     RETURN NEXT attr_set; CONTINUE; 
341                 END IF;
342             END IF;
343
344             IF tmp_attr_set.clib != '' THEN
345                 SELECT id INTO attr_set.circ_lib FROM actor.org_unit WHERE shortname = UPPER(tmp_attr_set.clib); -- INT
346                 IF NOT FOUND THEN
347                     attr_set.import_error := 'import.item.invalid.circ_lib';
348                     attr_set.error_detail := tmp_attr_set.clib;
349                     RETURN NEXT attr_set; CONTINUE; 
350                 END IF;
351             END IF;
352
353             IF tmp_attr_set.cs != '' THEN
354                 SELECT id INTO attr_set.status FROM config.copy_status WHERE LOWER(name) = LOWER(tmp_attr_set.cs); -- INT
355                 IF NOT FOUND THEN
356                     attr_set.import_error := 'import.item.invalid.status';
357                     attr_set.error_detail := tmp_attr_set.cs;
358                     RETURN NEXT attr_set; CONTINUE; 
359                 END IF;
360             END IF;
361
362             IF tmp_attr_set.circ_mod != '' THEN
363                 SELECT code INTO attr_set.circ_modifier FROM config.circ_modifier WHERE code = tmp_attr_set.circ_mod;
364                 IF NOT FOUND THEN
365                     attr_set.import_error := 'import.item.invalid.circ_modifier';
366                     attr_set.error_detail := tmp_attr_set.circ_mod;
367                     RETURN NEXT attr_set; CONTINUE; 
368                 END IF;
369             END IF;
370
371             IF tmp_attr_set.circ_as != '' THEN
372                 SELECT code INTO attr_set.circ_as_type FROM config.coded_value_map WHERE ctype = 'item_type' AND code = tmp_attr_set.circ_as;
373                 IF NOT FOUND THEN
374                     attr_set.import_error := 'import.item.invalid.circ_as_type';
375                     attr_set.error_detail := tmp_attr_set.circ_as;
376                     RETURN NEXT attr_set; CONTINUE; 
377                 END IF;
378             END IF;
379
380             IF tmp_attr_set.cl != '' THEN
381
382                 -- search up the org unit tree for a matching copy location
383                 WITH RECURSIVE anscestor_depth AS (
384                     SELECT  ou.id,
385                         out.depth AS depth,
386                         ou.parent_ou
387                     FROM  actor.org_unit ou
388                         JOIN actor.org_unit_type out ON (out.id = ou.ou_type)
389                     WHERE ou.id = COALESCE(attr_set.owning_lib, attr_set.circ_lib)
390                         UNION ALL
391                     SELECT  ou.id,
392                         out.depth,
393                         ou.parent_ou
394                     FROM  actor.org_unit ou
395                         JOIN actor.org_unit_type out ON (out.id = ou.ou_type)
396                         JOIN anscestor_depth ot ON (ot.parent_ou = ou.id)
397                 ) SELECT  cpl.id INTO attr_set.location
398                     FROM  anscestor_depth a
399                         JOIN asset.copy_location cpl ON (cpl.owning_lib = a.id)
400                     WHERE LOWER(cpl.name) = LOWER(tmp_attr_set.cl)
401                     ORDER BY a.depth DESC
402                     LIMIT 1; 
403
404                 IF NOT FOUND THEN
405                     attr_set.import_error := 'import.item.invalid.location';
406                     attr_set.error_detail := tmp_attr_set.cs;
407                     RETURN NEXT attr_set; CONTINUE; 
408                 END IF;
409             END IF;
410
411             attr_set.circulate      :=
412                 LOWER( SUBSTRING( tmp_attr_set.circ, 1, 1)) IN ('t','y','1')
413                 OR LOWER(tmp_attr_set.circ) = 'circulating'; -- BOOL
414
415             attr_set.deposit        :=
416                 LOWER( SUBSTRING( tmp_attr_set.dep, 1, 1 ) ) IN ('t','y','1')
417                 OR LOWER(tmp_attr_set.dep) = 'deposit'; -- BOOL
418
419             attr_set.holdable       :=
420                 LOWER( SUBSTRING( tmp_attr_set.hold, 1, 1 ) ) IN ('t','y','1')
421                 OR LOWER(tmp_attr_set.hold) = 'holdable'; -- BOOL
422
423             attr_set.opac_visible   :=
424                 LOWER( SUBSTRING( tmp_attr_set.opac_vis, 1, 1 ) ) IN ('t','y','1')
425                 OR LOWER(tmp_attr_set.opac_vis) = 'visible'; -- BOOL
426
427             attr_set.ref            :=
428                 LOWER( SUBSTRING( tmp_attr_set.r, 1, 1 ) ) IN ('t','y','1')
429                 OR LOWER(tmp_attr_set.r) = 'reference'; -- BOOL
430
431             attr_set.call_number    := tmp_attr_set.cn; -- TEXT
432             attr_set.barcode        := tmp_attr_set.bc; -- TEXT,
433             attr_set.alert_message  := tmp_attr_set.amessage; -- TEXT,
434             attr_set.pub_note       := tmp_attr_set.note; -- TEXT,
435             attr_set.priv_note      := tmp_attr_set.pnote; -- TEXT,
436             attr_set.alert_message  := tmp_attr_set.amessage; -- TEXT,
437             attr_set.internal_id    := tmp_attr_set.internal_id::BIGINT;
438
439             RETURN NEXT attr_set;
440
441         END LOOP;
442
443     END IF;
444
445     RETURN;
446
447 END;
448 $$ LANGUAGE PLPGSQL;
449
450
451
452 COMMIT;