]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/sql/Pg/upgrade/XXXX.function.located_uris_act_as_copies.sql
b531ed85882ec6e03a6bc6cde96f6d7cbc5c0532
[working/Evergreen.git] / Open-ILS / src / sql / Pg / upgrade / XXXX.function.located_uris_act_as_copies.sql
1 /*
2  * Copyright (C) 2014  Equinox Software, Inc.
3  * Mike Rylander <miker@esilibrary.com>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16
17
18 BEGIN;
19
20 INSERT INTO config.global_flag (name, enabled, label)
21 VALUES (
22     'opac.located_uri.act_as_copy',
23     FALSE,
24     oils_i18n_gettext(
25         'opac.located_uri.act_as_copy',
26         'When enabled, Located URIs will provide visiblity behavior identical to copies.',
27         'cgf',
28         'label'
29     )
30 );
31
32
33 CREATE OR REPLACE FUNCTION search.query_parser_fts (
34
35     param_search_ou INT,
36     param_depth     INT,
37     param_query     TEXT,
38     param_statuses  INT[],
39     param_locations INT[],
40     param_offset    INT,
41     param_check     INT,
42     param_limit     INT,
43     metarecord      BOOL,
44     staff           BOOL,
45     deleted_search  BOOL,
46     param_pref_ou   INT DEFAULT NULL
47 ) RETURNS SETOF search.search_result AS $func$
48 DECLARE
49
50     current_res         search.search_result%ROWTYPE;
51     search_org_list     INT[];
52     luri_org_list       INT[];
53     tmp_int_list        INT[];
54
55     check_limit         INT;
56     core_limit          INT;
57     core_offset         INT;
58     tmp_int             INT;
59
60     core_result         RECORD;
61     core_cursor         REFCURSOR;
62     core_rel_query      TEXT;
63
64     total_count         INT := 0;
65     check_count         INT := 0;
66     deleted_count       INT := 0;
67     visible_count       INT := 0;
68     excluded_count      INT := 0;
69
70     luri_as_copy        BOOL;
71 BEGIN
72
73     check_limit := COALESCE( param_check, 1000 );
74     core_limit  := COALESCE( param_limit, 25000 );
75     core_offset := COALESCE( param_offset, 0 );
76
77     SELECT COALESCE( enabled, FALSE ) INTO luri_as_copy FROM config.global_flag WHERE name = 'opac.located_uri.act_as_copy';
78
79     -- core_skip_chk := COALESCE( param_skip_chk, 1 );
80
81     IF param_search_ou > 0 THEN
82         IF param_depth IS NOT NULL THEN
83             SELECT array_accum(distinct id) INTO search_org_list FROM actor.org_unit_descendants( param_search_ou, param_depth );
84         ELSE
85             SELECT array_accum(distinct id) INTO search_org_list FROM actor.org_unit_descendants( param_search_ou );
86         END IF;
87
88         IF luri_as_copy THEN
89             SELECT array_accum(distinct id) INTO luri_org_list FROM actor.org_unit_full_path( param_search_ou );
90         ELSE
91             SELECT array_accum(distinct id) INTO luri_org_list FROM actor.org_unit_ancestors( param_search_ou );
92         END IF;
93
94     ELSIF param_search_ou < 0 THEN
95         SELECT array_accum(distinct org_unit) INTO search_org_list FROM actor.org_lasso_map WHERE lasso = -param_search_ou;
96
97         FOR tmp_int IN SELECT * FROM UNNEST(search_org_list) LOOP
98
99             IF luri_as_copy THEN
100                 SELECT array_accum(distinct id) INTO tmp_int_list FROM actor.org_unit_full_path( tmp_int );
101             ELSE
102                 SELECT array_accum(distinct id) INTO tmp_int_list FROM actor.org_unit_ancestors( tmp_int );
103             END IF;
104
105             luri_org_list := luri_org_list || tmp_int_list;
106         END LOOP;
107
108         SELECT array_accum(DISTINCT x.id) INTO luri_org_list FROM UNNEST(luri_org_list) x(id);
109
110     ELSIF param_search_ou = 0 THEN
111         -- reserved for user lassos (ou_buckets/type='lasso') with ID passed in depth ... hack? sure.
112     END IF;
113
114     IF param_pref_ou IS NOT NULL THEN
115             IF luri_as_copy THEN
116                 SELECT array_accum(distinct id) INTO tmp_int_list FROM actor.org_unit_full_path( param_pref_ou );
117             ELSE
118                 SELECT array_accum(distinct id) INTO tmp_int_list FROM actor.org_unit_ancestors( param_pref_ou );
119             END IF;
120
121         luri_org_list := luri_org_list || tmp_int_list;
122     END IF;
123
124     OPEN core_cursor FOR EXECUTE param_query;
125
126     LOOP
127
128         FETCH core_cursor INTO core_result;
129         EXIT WHEN NOT FOUND;
130         EXIT WHEN total_count >= core_limit;
131
132         total_count := total_count + 1;
133
134         CONTINUE WHEN total_count NOT BETWEEN  core_offset + 1 AND check_limit + core_offset;
135
136         check_count := check_count + 1;
137
138         IF NOT deleted_search THEN
139
140             PERFORM 1 FROM biblio.record_entry b WHERE NOT b.deleted AND b.id IN ( SELECT * FROM unnest( core_result.records ) );
141             IF NOT FOUND THEN
142                 -- RAISE NOTICE ' % were all deleted ... ', core_result.records;
143                 deleted_count := deleted_count + 1;
144                 CONTINUE;
145             END IF;
146
147             PERFORM 1
148               FROM  biblio.record_entry b
149                     JOIN config.bib_source s ON (b.source = s.id)
150               WHERE s.transcendant
151                     AND b.id IN ( SELECT * FROM unnest( core_result.records ) );
152
153             IF FOUND THEN
154                 -- RAISE NOTICE ' % were all transcendant ... ', core_result.records;
155                 visible_count := visible_count + 1;
156
157                 current_res.id = core_result.id;
158                 current_res.rel = core_result.rel;
159
160                 tmp_int := 1;
161                 IF metarecord THEN
162                     SELECT COUNT(DISTINCT s.source) INTO tmp_int FROM metabib.metarecord_source_map s WHERE s.metarecord = core_result.id;
163                 END IF;
164
165                 IF tmp_int = 1 THEN
166                     current_res.record = core_result.records[1];
167                 ELSE
168                     current_res.record = NULL;
169                 END IF;
170
171                 RETURN NEXT current_res;
172
173                 CONTINUE;
174             END IF;
175
176             PERFORM 1
177               FROM  asset.call_number cn
178                     JOIN asset.uri_call_number_map map ON (map.call_number = cn.id)
179                     JOIN asset.uri uri ON (map.uri = uri.id)
180               WHERE NOT cn.deleted
181                     AND cn.label = '##URI##'
182                     AND uri.active
183                     AND ( param_locations IS NULL OR array_upper(param_locations, 1) IS NULL )
184                     AND cn.record IN ( SELECT * FROM unnest( core_result.records ) )
185                     AND cn.owning_lib IN ( SELECT * FROM unnest( luri_org_list ) )
186               LIMIT 1;
187
188             IF FOUND THEN
189                 -- RAISE NOTICE ' % have at least one URI ... ', core_result.records;
190                 visible_count := visible_count + 1;
191
192                 current_res.id = core_result.id;
193                 current_res.rel = core_result.rel;
194
195                 tmp_int := 1;
196                 IF metarecord THEN
197                     SELECT COUNT(DISTINCT s.source) INTO tmp_int FROM metabib.metarecord_source_map s WHERE s.metarecord = core_result.id;
198                 END IF;
199
200                 IF tmp_int = 1 THEN
201                     current_res.record = core_result.records[1];
202                 ELSE
203                     current_res.record = NULL;
204                 END IF;
205
206                 RETURN NEXT current_res;
207
208                 CONTINUE;
209             END IF;
210
211             IF param_statuses IS NOT NULL AND array_upper(param_statuses, 1) > 0 THEN
212
213                 PERFORM 1
214                   FROM  asset.call_number cn
215                         JOIN asset.copy cp ON (cp.call_number = cn.id)
216                   WHERE NOT cn.deleted
217                         AND NOT cp.deleted
218                         AND cp.status IN ( SELECT * FROM unnest( param_statuses ) )
219                         AND cn.record IN ( SELECT * FROM unnest( core_result.records ) )
220                         AND cp.circ_lib IN ( SELECT * FROM unnest( search_org_list ) )
221                   LIMIT 1;
222
223                 IF NOT FOUND THEN
224                     PERFORM 1
225                       FROM  biblio.peer_bib_copy_map pr
226                             JOIN asset.copy cp ON (cp.id = pr.target_copy)
227                       WHERE NOT cp.deleted
228                             AND cp.status IN ( SELECT * FROM unnest( param_statuses ) )
229                             AND pr.peer_record IN ( SELECT * FROM unnest( core_result.records ) )
230                             AND cp.circ_lib IN ( SELECT * FROM unnest( search_org_list ) )
231                       LIMIT 1;
232
233                     IF NOT FOUND THEN
234                     -- RAISE NOTICE ' % and multi-home linked records were all status-excluded ... ', core_result.records;
235                         excluded_count := excluded_count + 1;
236                         CONTINUE;
237                     END IF;
238                 END IF;
239
240             END IF;
241
242             IF param_locations IS NOT NULL AND array_upper(param_locations, 1) > 0 THEN
243
244                 PERFORM 1
245                   FROM  asset.call_number cn
246                         JOIN asset.copy cp ON (cp.call_number = cn.id)
247                   WHERE NOT cn.deleted
248                         AND NOT cp.deleted
249                         AND cp.location IN ( SELECT * FROM unnest( param_locations ) )
250                         AND cn.record IN ( SELECT * FROM unnest( core_result.records ) )
251                         AND cp.circ_lib IN ( SELECT * FROM unnest( search_org_list ) )
252                   LIMIT 1;
253
254                 IF NOT FOUND THEN
255                     PERFORM 1
256                       FROM  biblio.peer_bib_copy_map pr
257                             JOIN asset.copy cp ON (cp.id = pr.target_copy)
258                       WHERE NOT cp.deleted
259                             AND cp.location IN ( SELECT * FROM unnest( param_locations ) )
260                             AND pr.peer_record IN ( SELECT * FROM unnest( core_result.records ) )
261                             AND cp.circ_lib IN ( SELECT * FROM unnest( search_org_list ) )
262                       LIMIT 1;
263
264                     IF NOT FOUND THEN
265                         -- RAISE NOTICE ' % and multi-home linked records were all copy_location-excluded ... ', core_result.records;
266                         excluded_count := excluded_count + 1;
267                         CONTINUE;
268                     END IF;
269                 END IF;
270
271             END IF;
272
273             IF staff IS NULL OR NOT staff THEN
274
275                 PERFORM 1
276                   FROM  asset.opac_visible_copies
277                   WHERE circ_lib IN ( SELECT * FROM unnest( search_org_list ) )
278                         AND record IN ( SELECT * FROM unnest( core_result.records ) )
279                   LIMIT 1;
280
281                 IF NOT FOUND THEN
282                     PERFORM 1
283                       FROM  biblio.peer_bib_copy_map pr
284                             JOIN asset.opac_visible_copies cp ON (cp.copy_id = pr.target_copy)
285                       WHERE cp.circ_lib IN ( SELECT * FROM unnest( search_org_list ) )
286                             AND pr.peer_record IN ( SELECT * FROM unnest( core_result.records ) )
287                       LIMIT 1;
288
289                     IF NOT FOUND THEN
290
291                         -- RAISE NOTICE ' % and multi-home linked records were all visibility-excluded ... ', core_result.records;
292                         excluded_count := excluded_count + 1;
293                         CONTINUE;
294                     END IF;
295                 END IF;
296
297             ELSE
298
299                 PERFORM 1
300                   FROM  asset.call_number cn
301                         JOIN asset.copy cp ON (cp.call_number = cn.id)
302                   WHERE NOT cn.deleted
303                         AND NOT cp.deleted
304                         AND cp.circ_lib IN ( SELECT * FROM unnest( search_org_list ) )
305                         AND cn.record IN ( SELECT * FROM unnest( core_result.records ) )
306                   LIMIT 1;
307
308                 IF NOT FOUND THEN
309
310                     PERFORM 1
311                       FROM  biblio.peer_bib_copy_map pr
312                             JOIN asset.copy cp ON (cp.id = pr.target_copy)
313                       WHERE NOT cp.deleted
314                             AND cp.circ_lib IN ( SELECT * FROM unnest( search_org_list ) )
315                             AND pr.peer_record IN ( SELECT * FROM unnest( core_result.records ) )
316                       LIMIT 1;
317
318                     IF NOT FOUND THEN
319
320                         PERFORM 1
321                           FROM  asset.call_number cn
322                                 JOIN asset.copy cp ON (cp.call_number = cn.id)
323                           WHERE cn.record IN ( SELECT * FROM unnest( core_result.records ) )
324                                 AND NOT cp.deleted
325                           LIMIT 1;
326
327                         IF FOUND THEN
328                             -- RAISE NOTICE ' % and multi-home linked records were all visibility-excluded ... ', core_result.records;
329                             excluded_count := excluded_count + 1;
330                             CONTINUE;
331                         END IF;
332                     END IF;
333
334                 END IF;
335
336             END IF;
337
338         END IF;
339
340         visible_count := visible_count + 1;
341
342         current_res.id = core_result.id;
343         current_res.rel = core_result.rel;
344
345         tmp_int := 1;
346         IF metarecord THEN
347             SELECT COUNT(DISTINCT s.source) INTO tmp_int FROM metabib.metarecord_source_map s WHERE s.metarecord = core_result.id;
348         END IF;
349
350         IF tmp_int = 1 THEN
351             current_res.record = core_result.records[1];
352         ELSE
353             current_res.record = NULL;
354         END IF;
355
356         RETURN NEXT current_res;
357
358         IF visible_count % 1000 = 0 THEN
359             -- RAISE NOTICE ' % visible so far ... ', visible_count;
360         END IF;
361
362     END LOOP;
363
364     current_res.id = NULL;
365     current_res.rel = NULL;
366     current_res.record = NULL;
367     current_res.total = total_count;
368     current_res.checked = check_count;
369     current_res.deleted = deleted_count;
370     current_res.visible = visible_count;
371     current_res.excluded = excluded_count;
372
373     CLOSE core_cursor;
374
375     RETURN NEXT current_res;
376
377 END;
378 $func$ LANGUAGE PLPGSQL;
379
380 CREATE OR REPLACE FUNCTION unapi.holdings_xml (
381     bid BIGINT,
382     ouid INT,
383     org TEXT,
384     depth INT DEFAULT NULL,
385     includes TEXT[] DEFAULT NULL::TEXT[],
386     slimit HSTORE DEFAULT NULL,
387     soffset HSTORE DEFAULT NULL,
388     include_xmlns BOOL DEFAULT TRUE,
389     pref_lib INT DEFAULT NULL
390 )
391 RETURNS XML AS $F$
392      SELECT  XMLELEMENT(
393                  name holdings,
394                  XMLATTRIBUTES(
395                     CASE WHEN $8 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
396                     CASE WHEN ('bre' = ANY ($5)) THEN 'tag:open-ils.org:U2@bre/' || $1 || '/' || $3 ELSE NULL END AS id,
397                     (SELECT record_has_holdable_copy FROM asset.record_has_holdable_copy($1)) AS has_holdable
398                  ),
399                  XMLELEMENT(
400                      name counts,
401                      (SELECT  XMLAGG(XMLELEMENT::XML) FROM (
402                          SELECT  XMLELEMENT(
403                                      name count,
404                                      XMLATTRIBUTES('public' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
405                                  )::text
406                            FROM  asset.opac_ou_record_copy_count($2,  $1)
407                                      UNION
408                          SELECT  XMLELEMENT(
409                                      name count,
410                                      XMLATTRIBUTES('staff' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
411                                  )::text
412                            FROM  asset.staff_ou_record_copy_count($2, $1)
413                                      UNION
414                          SELECT  XMLELEMENT(
415                                      name count,
416                                      XMLATTRIBUTES('pref_lib' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
417                                  )::text
418                            FROM  asset.opac_ou_record_copy_count($9,  $1)
419                                      ORDER BY 1
420                      )x)
421                  ),
422                  CASE
423                      WHEN ('bmp' = ANY ($5)) THEN
424                         XMLELEMENT(
425                             name monograph_parts,
426                             (SELECT XMLAGG(bmp) FROM (
427                                 SELECT  unapi.bmp( id, 'xml', 'monograph_part', evergreen.array_remove_item_by_value( evergreen.array_remove_item_by_value($5,'bre'), 'holdings_xml'), $3, $4, $6, $7, FALSE)
428                                   FROM  biblio.monograph_part
429                                   WHERE record = $1
430                             )x)
431                         )
432                      ELSE NULL
433                  END,
434                  XMLELEMENT(
435                      name volumes,
436                      (SELECT XMLAGG(acn ORDER BY rank, name, label_sortkey) FROM (
437                         -- Physical copies
438                         SELECT  unapi.acn(y.id,'xml','volume',evergreen.array_remove_item_by_value( evergreen.array_remove_item_by_value($5,'holdings_xml'),'bre'), $3, $4, $6, $7, FALSE), y.rank, name, label_sortkey
439                         FROM evergreen.ranked_volumes($1, $2, $4, $6, $7, $9, $5) AS y
440                         UNION ALL
441                         -- Located URIs
442                         SELECT unapi.acn(uris.id,'xml','volume',evergreen.array_remove_item_by_value( evergreen.array_remove_item_by_value($5,'holdings_xml'),'bre'), $3, $4, $6, $7, FALSE), uris.rank, name, label_sortkey
443                         FROM evergreen.located_uris($1, $2, $9) AS uris
444                      )x)
445                  ),
446                  CASE WHEN ('ssub' = ANY ($5)) THEN
447                      XMLELEMENT(
448                          name subscriptions,
449                          (SELECT XMLAGG(ssub) FROM (
450                             SELECT  unapi.ssub(id,'xml','subscription','{}'::TEXT[], $3, $4, $6, $7, FALSE)
451                               FROM  serial.subscription
452                               WHERE record_entry = $1
453                         )x)
454                      )
455                  ELSE NULL END,
456                  CASE WHEN ('acp' = ANY ($5)) THEN
457                      XMLELEMENT(
458                          name foreign_copies,
459                          (SELECT XMLAGG(acp) FROM (
460                             SELECT  unapi.acp(p.target_copy,'xml','copy',evergreen.array_remove_item_by_value($5,'acp'), $3, $4, $6, $7, FALSE)
461                               FROM  biblio.peer_bib_copy_map p
462                                     JOIN asset.copy c ON (p.target_copy = c.id)
463                               WHERE NOT c.deleted AND p.peer_record = $1
464                             LIMIT ($6 -> 'acp')::INT
465                             OFFSET ($7 -> 'acp')::INT
466                         )x)
467                      )
468                  ELSE NULL END
469              );
470 $F$ LANGUAGE SQL STABLE;
471
472 COMMIT;
473