]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/sql/Pg/040.schema.asset.sql
Add an index on asset.copy(create_date) for item-age browse
[working/Evergreen.git] / Open-ILS / src / sql / Pg / 040.schema.asset.sql
1 /*
2  * Copyright (C) 2004-2008  Georgia Public Library Service
3  * Copyright (C) 2007-2008  Equinox Software, Inc.
4  * Mike Rylander <miker@esilibrary.com> 
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  */
17
18 DROP SCHEMA IF EXISTS asset CASCADE;
19
20 BEGIN;
21
22 CREATE SCHEMA asset;
23
24 CREATE TABLE asset.copy_location (
25         id              SERIAL  PRIMARY KEY,
26         name            TEXT    NOT NULL,
27         owning_lib      INT     NOT NULL REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED,
28         holdable        BOOL    NOT NULL DEFAULT TRUE,
29         hold_verify     BOOL    NOT NULL DEFAULT FALSE,
30         opac_visible    BOOL    NOT NULL DEFAULT TRUE,
31         circulate       BOOL    NOT NULL DEFAULT TRUE,
32         label_prefix    TEXT,
33         label_suffix    TEXT,
34         CONSTRAINT acl_name_once_per_lib UNIQUE (name, owning_lib)
35 );
36
37 CREATE TABLE asset.copy_location_order
38 (
39         id              SERIAL           PRIMARY KEY,
40         location        INT              NOT NULL
41                                              REFERENCES asset.copy_location
42                                              ON DELETE CASCADE
43                                              DEFERRABLE INITIALLY DEFERRED,
44         org             INT              NOT NULL
45                                              REFERENCES actor.org_unit
46                                              ON DELETE CASCADE
47                                              DEFERRABLE INITIALLY DEFERRED,
48         position        INT              NOT NULL DEFAULT 0,
49         CONSTRAINT acplo_once_per_org UNIQUE ( location, org )
50 );
51
52 CREATE TABLE asset.copy (
53         id              BIGSERIAL                       PRIMARY KEY,
54         circ_lib        INT                             NOT NULL REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED,
55         creator         BIGINT                          NOT NULL,
56         call_number     BIGINT                          NOT NULL,
57         editor          BIGINT                          NOT NULL,
58         create_date     TIMESTAMP WITH TIME ZONE        DEFAULT NOW(),
59         edit_date       TIMESTAMP WITH TIME ZONE        DEFAULT NOW(),
60         copy_number     INT,
61         status          INT                             NOT NULL DEFAULT 0 REFERENCES config.copy_status (id) DEFERRABLE INITIALLY DEFERRED,
62         location        INT                             NOT NULL DEFAULT 1 REFERENCES asset.copy_location (id) DEFERRABLE INITIALLY DEFERRED,
63         loan_duration   INT                             NOT NULL CHECK ( loan_duration IN (1,2,3) ),
64         fine_level      INT                             NOT NULL CHECK ( fine_level IN (1,2,3) ),
65         age_protect     INT,
66         circulate       BOOL                            NOT NULL DEFAULT TRUE,
67         deposit         BOOL                            NOT NULL DEFAULT FALSE,
68         ref             BOOL                            NOT NULL DEFAULT FALSE,
69         holdable        BOOL                            NOT NULL DEFAULT TRUE,
70         deposit_amount  NUMERIC(6,2)                    NOT NULL DEFAULT 0.00,
71         price           NUMERIC(8,2),
72         barcode         TEXT                            NOT NULL,
73         circ_modifier   TEXT,
74         circ_as_type    TEXT,
75         dummy_title     TEXT,
76         dummy_author    TEXT,
77         alert_message   TEXT,
78         opac_visible    BOOL                            NOT NULL DEFAULT TRUE,
79         deleted         BOOL                            NOT NULL DEFAULT FALSE,
80         floating                BOOL                            NOT NULL DEFAULT FALSE,
81         dummy_isbn      TEXT,
82         status_changed_time TIMESTAMP WITH TIME ZONE,
83         mint_condition      BOOL        NOT NULL DEFAULT TRUE,
84     cost    NUMERIC(8,2)
85 );
86 CREATE UNIQUE INDEX copy_barcode_key ON asset.copy (barcode) WHERE deleted = FALSE OR deleted IS FALSE;
87 CREATE INDEX cp_cn_idx ON asset.copy (call_number);
88 CREATE INDEX cp_avail_cn_idx ON asset.copy (call_number);
89 CREATE INDEX cp_creator_idx  ON asset.copy ( creator );
90 CREATE INDEX cp_editor_idx   ON asset.copy ( editor );
91 CREATE INDEX cp_create_date  ON asset.copy (create_date);
92 CREATE RULE protect_copy_delete AS ON DELETE TO asset.copy DO INSTEAD UPDATE asset.copy SET deleted = TRUE WHERE OLD.id = asset.copy.id;
93
94 CREATE TABLE asset.opac_visible_copies (
95   id        BIGINT primary key, -- copy id
96   record    BIGINT,
97   circ_lib  INTEGER
98 );
99 COMMENT ON TABLE asset.opac_visible_copies IS $$
100 Materialized view of copies that are visible in the OPAC, used by
101 search.query_parser_fts() to speed up OPAC visibility checks on large
102 databases.  Contents are maintained by a set of triggers.
103 $$;
104 CREATE INDEX opac_visible_copies_idx1 on asset.opac_visible_copies (record, circ_lib);
105
106 CREATE OR REPLACE FUNCTION asset.acp_status_changed()
107 RETURNS TRIGGER AS $$
108 BEGIN
109     IF NEW.status <> OLD.status THEN
110         NEW.status_changed_time := now();
111     END IF;
112     RETURN NEW;
113 END;
114 $$ LANGUAGE plpgsql;
115
116 CREATE TRIGGER acp_status_changed_trig
117     BEFORE UPDATE ON asset.copy
118     FOR EACH ROW EXECUTE PROCEDURE asset.acp_status_changed();
119
120 CREATE TABLE asset.stat_cat_entry_transparency_map (
121         id                      BIGSERIAL       PRIMARY KEY,
122         stat_cat                INT             NOT NULL, -- needs ON DELETE CASCADE
123         stat_cat_entry          INT             NOT NULL, -- needs ON DELETE CASCADE
124         owning_transparency     INT             NOT NULL, -- needs ON DELETE CASCADE
125         CONSTRAINT scte_once_per_trans UNIQUE (owning_transparency,stat_cat)
126 );
127
128 CREATE TABLE asset.stat_cat (
129         id              SERIAL  PRIMARY KEY,
130         owner           INT     NOT NULL,
131         opac_visible    BOOL    NOT NULL DEFAULT FALSE,
132         name            TEXT    NOT NULL,
133         required        BOOL    NOT NULL DEFAULT FALSE,
134         CONSTRAINT sc_once_per_owner UNIQUE (owner,name)
135 );
136
137 CREATE TABLE asset.stat_cat_entry (
138         id              SERIAL  PRIMARY KEY,
139         stat_cat        INT     NOT NULL,
140         owner           INT     NOT NULL,
141         value           TEXT    NOT NULL,
142         CONSTRAINT sce_once_per_owner UNIQUE (stat_cat,owner,value)
143 );
144
145 CREATE TABLE asset.stat_cat_entry_copy_map (
146         id              BIGSERIAL       PRIMARY KEY,
147         stat_cat        INT             NOT NULL,
148         stat_cat_entry  INT             NOT NULL,
149         owning_copy     BIGINT          NOT NULL,
150         CONSTRAINT sce_once_per_copy UNIQUE (owning_copy,stat_cat)
151 );
152 CREATE INDEX scecm_owning_copy_idx ON asset.stat_cat_entry_copy_map(owning_copy);
153
154 CREATE TABLE asset.copy_note (
155         id              BIGSERIAL                       PRIMARY KEY,
156         owning_copy     BIGINT                          NOT NULL,
157         creator         BIGINT                          NOT NULL,
158         create_date     TIMESTAMP WITH TIME ZONE        DEFAULT NOW(),
159         pub             BOOL                            NOT NULL DEFAULT FALSE,
160         title           TEXT                            NOT NULL,
161         value           TEXT                            NOT NULL
162 );
163 CREATE INDEX asset_copy_note_creator_idx ON asset.copy_note ( creator );
164 CREATE INDEX asset_copy_note_owning_copy_idx ON asset.copy_note ( owning_copy );
165
166 CREATE TABLE asset.uri (
167     id  SERIAL  PRIMARY KEY,
168     href    TEXT    NOT NULL,
169     label   TEXT,
170     use_restriction TEXT,
171     active  BOOL    NOT NULL DEFAULT TRUE
172 );
173
174 CREATE TABLE asset.call_number_class (
175     id             bigserial     PRIMARY KEY,
176     name           TEXT          NOT NULL,
177     normalizer     TEXT          NOT NULL DEFAULT 'asset.normalize_generic',
178     field          TEXT          NOT NULL DEFAULT '050ab,055ab,060ab,070ab,080ab,082ab,086ab,088ab,090,092,096,098,099'
179 );
180 COMMENT ON TABLE asset.call_number_class IS $$
181 Defines the call number normalization database functions in the "normalizer"
182 column and the tag/subfield combinations to use to lookup the call number in
183 the "field" column for a given classification scheme. Tag/subfield combinations
184 are delimited by commas.
185 $$;
186
187 CREATE OR REPLACE FUNCTION asset.label_normalizer() RETURNS TRIGGER AS $func$
188 DECLARE
189     sortkey        TEXT := '';
190 BEGIN
191     sortkey := NEW.label_sortkey;
192
193     EXECUTE 'SELECT ' || acnc.normalizer || '(' || 
194        quote_literal( NEW.label ) || ')'
195        FROM asset.call_number_class acnc
196        WHERE acnc.id = NEW.label_class
197        INTO sortkey;
198
199     NEW.label_sortkey = sortkey;
200
201     RETURN NEW;
202 END;
203 $func$ LANGUAGE PLPGSQL;
204
205 CREATE OR REPLACE FUNCTION asset.label_normalizer_generic(TEXT) RETURNS TEXT AS $func$
206     # Created after looking at the Koha C4::ClassSortRoutine::Generic module,
207     # thus could probably be considered a derived work, although nothing was
208     # directly copied - but to err on the safe side of providing attribution:
209     # Copyright (C) 2007 LibLime
210     # Licensed under the GPL v2 or later
211
212     use strict;
213     use warnings;
214
215     # Converts the callnumber to uppercase
216     # Strips spaces from start and end of the call number
217     # Converts anything other than letters, digits, and periods into underscores
218     # Collapses multiple underscores into a single underscore
219     my $callnum = uc(shift);
220     $callnum =~ s/^\s//g;
221     $callnum =~ s/\s$//g;
222     $callnum =~ s/[^A-Z0-9_.]/_/g;
223     $callnum =~ s/_{2,}/_/g;
224
225     return $callnum;
226 $func$ LANGUAGE PLPERLU;
227
228 CREATE OR REPLACE FUNCTION asset.label_normalizer_dewey(TEXT) RETURNS TEXT AS $func$
229     # Derived from the Koha C4::ClassSortRoutine::Dewey module
230     # Copyright (C) 2007 LibLime
231     # Licensed under the GPL v2 or later
232
233     use strict;
234     use warnings;
235
236     my $init = uc(shift);
237     $init =~ s/^\s+//;
238     $init =~ s/\s+$//;
239     $init =~ s!/!!g;
240     $init =~ s/^([\p{IsAlpha}]+)/$1 /;
241     my @tokens = split /\.|\s+/, $init;
242     my $digit_group_count = 0;
243     for (my $i = 0; $i <= $#tokens; $i++) {
244         if ($tokens[$i] =~ /^\d+$/) {
245             $digit_group_count++;
246             if (2 == $digit_group_count) {
247                 $tokens[$i] = sprintf("%-15.15s", $tokens[$i]);
248                 $tokens[$i] =~ tr/ /0/;
249             }
250         }
251     }
252     my $key = join("_", @tokens);
253     $key =~ s/[^\p{IsAlnum}_]//g;
254
255     return $key;
256
257 $func$ LANGUAGE PLPERLU;
258
259 CREATE OR REPLACE FUNCTION asset.label_normalizer_lc(TEXT) RETURNS TEXT AS $func$
260     use strict;
261     use warnings;
262
263     # Library::CallNumber::LC is currently hosted at http://code.google.com/p/library-callnumber-lc/
264     # The author hopes to upload it to CPAN some day, which would make our lives easier
265     use Library::CallNumber::LC;
266
267     my $callnum = Library::CallNumber::LC->new(shift);
268     return $callnum->normalize();
269
270 $func$ LANGUAGE PLPERLU;
271
272 INSERT INTO asset.call_number_class (name, normalizer, field) VALUES 
273     ('Generic', 'asset.label_normalizer_generic', '050ab,055ab,060ab,070ab,080ab,082ab,086ab,088ab,090,092,096,098,099'),
274     ('Dewey (DDC)', 'asset.label_normalizer_dewey', '080ab,082ab'),
275     ('Library of Congress (LC)', 'asset.label_normalizer_lc', '050ab,055ab')
276 ;
277
278 CREATE TABLE asset.call_number (
279         id              bigserial PRIMARY KEY,
280         creator         BIGINT                          NOT NULL,
281         create_date     TIMESTAMP WITH TIME ZONE        DEFAULT NOW(),
282         editor          BIGINT                          NOT NULL,
283         edit_date       TIMESTAMP WITH TIME ZONE        DEFAULT NOW(),
284         record          bigint                          NOT NULL,
285         owning_lib      INT                             NOT NULL,
286         label           TEXT                            NOT NULL,
287         deleted         BOOL                            NOT NULL DEFAULT FALSE,
288         label_class     BIGINT                          DEFAULT 1 NOT NULL
289                                                         REFERENCES asset.call_number_class(id)
290                                                         DEFERRABLE INITIALLY DEFERRED,
291         label_sortkey   TEXT
292 );
293 CREATE INDEX asset_call_number_record_idx ON asset.call_number (record);
294 CREATE INDEX asset_call_number_creator_idx ON asset.call_number (creator);
295 CREATE INDEX asset_call_number_editor_idx ON asset.call_number (editor);
296 CREATE INDEX asset_call_number_dewey_idx ON asset.call_number (public.call_number_dewey(label));
297 CREATE INDEX asset_call_number_upper_label_id_owning_lib_idx ON asset.call_number (oils_text_as_bytea(label),id,owning_lib);
298 CREATE INDEX asset_call_number_label_sortkey ON asset.call_number(oils_text_as_bytea(label_sortkey));
299 CREATE UNIQUE INDEX asset_call_number_label_once_per_lib ON asset.call_number (record, owning_lib, label) WHERE deleted = FALSE OR deleted IS FALSE;
300 CREATE RULE protect_cn_delete AS ON DELETE TO asset.call_number DO INSTEAD UPDATE asset.call_number SET deleted = TRUE WHERE OLD.id = asset.call_number.id;
301 CREATE TRIGGER asset_label_sortkey_trigger
302     BEFORE UPDATE OR INSERT ON asset.call_number
303     FOR EACH ROW EXECUTE PROCEDURE asset.label_normalizer();
304
305 CREATE TABLE asset.uri_call_number_map (
306     id          BIGSERIAL   PRIMARY KEY,
307     uri         INT         NOT NULL REFERENCES asset.uri (id),
308     call_number INT         NOT NULL REFERENCES asset.call_number (id),
309     CONSTRAINT uri_cn_once UNIQUE (uri,call_number)
310 );
311 CREATE INDEX asset_uri_call_number_map_cn_idx ON asset.uri_call_number_map (call_number);
312
313 CREATE TABLE asset.call_number_note (
314         id              BIGSERIAL                       PRIMARY KEY,
315         call_number     BIGINT                          NOT NULL,
316         creator         BIGINT                          NOT NULL,
317         create_date     TIMESTAMP WITH TIME ZONE        DEFAULT NOW(),
318         pub             BOOL                            NOT NULL DEFAULT FALSE,
319         title           TEXT                            NOT NULL,
320         value           TEXT                            NOT NULL
321 );
322 CREATE INDEX asset_call_number_note_creator_idx ON asset.call_number_note ( creator );
323
324 CREATE TABLE asset.copy_template (
325         id             SERIAL   PRIMARY KEY,
326         owning_lib     INT      NOT NULL
327                                 REFERENCES actor.org_unit (id)
328                                 DEFERRABLE INITIALLY DEFERRED,
329         creator        BIGINT   NOT NULL
330                                 REFERENCES actor.usr (id)
331                                 DEFERRABLE INITIALLY DEFERRED,
332         editor         BIGINT   NOT NULL
333                                 REFERENCES actor.usr (id)
334                                 DEFERRABLE INITIALLY DEFERRED,
335         create_date    TIMESTAMP WITH TIME ZONE    DEFAULT NOW(),
336         edit_date      TIMESTAMP WITH TIME ZONE    DEFAULT NOW(),
337         name           TEXT     NOT NULL,
338         -- columns above this point are attributes of the template itself
339         -- columns after this point are attributes of the copy this template modifies/creates
340         circ_lib       INT      REFERENCES actor.org_unit (id)
341                                 DEFERRABLE INITIALLY DEFERRED,
342         status         INT      REFERENCES config.copy_status (id)
343                                 DEFERRABLE INITIALLY DEFERRED,
344         location       INT      REFERENCES asset.copy_location (id)
345                                 DEFERRABLE INITIALLY DEFERRED,
346         loan_duration  INT      CONSTRAINT valid_loan_duration CHECK (
347                                     loan_duration IS NULL OR loan_duration IN (1,2,3)),
348         fine_level     INT      CONSTRAINT valid_fine_level CHECK (
349                                     fine_level IS NULL OR loan_duration IN (1,2,3)),
350         age_protect    INT,
351         circulate      BOOL,
352         deposit        BOOL,
353         ref            BOOL,
354         holdable       BOOL,
355         deposit_amount NUMERIC(6,2),
356         price          NUMERIC(8,2),
357         circ_modifier  TEXT,
358         circ_as_type   TEXT,
359         alert_message  TEXT,
360         opac_visible   BOOL,
361         floating       BOOL,
362         mint_condition BOOL
363 );
364
365 CREATE VIEW stats.fleshed_copy AS 
366         SELECT  cp.*,
367                 CAST(cp.create_date AS DATE) AS create_date_day,
368                 CAST(cp.edit_date AS DATE) AS edit_date_day,
369                 DATE_TRUNC('hour', cp.create_date) AS create_date_hour,
370                 DATE_TRUNC('hour', cp.edit_date) AS edit_date_hour,
371                 cn.label AS call_number_label,
372                 cn.owning_lib,
373                 rd.item_lang,
374                 rd.item_type,
375                 rd.item_form
376         FROM    asset.copy cp
377                 JOIN asset.call_number cn ON (cp.call_number = cn.id)
378                 JOIN metabib.rec_descriptor rd ON (rd.record = cn.record);
379
380 CREATE VIEW stats.fleshed_call_number AS 
381         SELECT  cn.*,
382                 CAST(cn.create_date AS DATE) AS create_date_day,
383                 CAST(cn.edit_date AS DATE) AS edit_date_day,
384                 DATE_TRUNC('hour', cn.create_date) AS create_date_hour,
385                 DATE_TRUNC('hour', cn.edit_date) AS edit_date_hour,
386                 rd.item_lang,
387                 rd.item_type,
388                 rd.item_form
389         FROM    asset.call_number cn
390                 JOIN metabib.rec_descriptor rd ON (rd.record = cn.record);
391
392 CREATE OR REPLACE FUNCTION asset.opac_ou_record_copy_count (org INT, record BIGINT) RETURNS TABLE (depth INT, org_unit INT, visible BIGINT, available BIGINT, unshadow BIGINT, transcendant INT) AS $f$
393 DECLARE
394     ans RECORD;
395     trans INT;
396 BEGIN
397     SELECT 1 INTO trans FROM biblio.record_entry b JOIN config.bib_source src ON (b.source = src.id) WHERE src.transcendant AND b.id = record;
398
399     FOR ans IN SELECT u.id, t.depth FROM actor.org_unit_ancestors(org) AS u JOIN actor.org_unit_type t ON (u.ou_type = t.id) LOOP
400         RETURN QUERY
401         SELECT  ans.depth,
402                 ans.id,
403                 COUNT( av.id ),
404                 SUM( CASE WHEN cp.status IN (0,7,12) THEN 1 ELSE 0 END ),
405                 COUNT( av.id ),
406                 trans
407           FROM  
408                 actor.org_unit_descendants(ans.id) d
409                 JOIN asset.opac_visible_copies av ON (av.record = record AND av.circ_lib = d.id)
410                 JOIN asset.copy cp ON (cp.id = av.id)
411           GROUP BY 1,2,6;
412
413         IF NOT FOUND THEN
414             RETURN QUERY SELECT ans.depth, ans.id, 0::BIGINT, 0::BIGINT, 0::BIGINT, trans;
415         END IF;
416
417     END LOOP;
418
419     RETURN;
420 END;
421 $f$ LANGUAGE PLPGSQL;
422
423 CREATE OR REPLACE FUNCTION asset.opac_lasso_record_copy_count (i_lasso INT, record BIGINT) RETURNS TABLE (depth INT, org_unit INT, visible BIGINT, available BIGINT, unshadow BIGINT, transcendant INT) AS $f$
424 DECLARE
425     ans RECORD;
426     trans INT;
427 BEGIN
428     SELECT 1 INTO trans FROM biblio.record_entry b JOIN config.bib_source src ON (b.source = src.id) WHERE src.transcendant AND b.id = record;
429
430     FOR ans IN SELECT u.org_unit AS id FROM actor.org_lasso_map AS u WHERE lasso = i_lasso LOOP
431         RETURN QUERY
432         SELECT  -1,
433                 ans.id,
434                 COUNT( av.id ),
435                 SUM( CASE WHEN cp.status IN (0,7,12) THEN 1 ELSE 0 END ),
436                 COUNT( av.id ),
437                 trans
438           FROM
439                 actor.org_unit_descendants(ans.id) d
440                 JOIN asset.opac_visible_copies av ON (av.record = record AND av.circ_lib = d.id)
441                 JOIN asset.copy cp ON (cp.id = av.id)
442           GROUP BY 1,2,6;
443
444         IF NOT FOUND THEN
445             RETURN QUERY SELECT ans.depth, ans.id, 0::BIGINT, 0::BIGINT, 0::BIGINT, trans;
446         END IF;
447
448     END LOOP;   
449                 
450     RETURN;     
451 END;            
452 $f$ LANGUAGE PLPGSQL;
453
454 CREATE OR REPLACE FUNCTION asset.staff_ou_record_copy_count (org INT, record BIGINT) RETURNS TABLE (depth INT, org_unit INT, visible BIGINT, available BIGINT, unshadow BIGINT, transcendant INT) AS $f$
455 DECLARE         
456     ans RECORD; 
457     trans INT;
458 BEGIN           
459     SELECT 1 INTO trans FROM biblio.record_entry b JOIN config.bib_source src ON (b.source = src.id) WHERE src.transcendant AND b.id = record;
460
461     FOR ans IN SELECT u.id, t.depth FROM actor.org_unit_ancestors(org) AS u JOIN actor.org_unit_type t ON (u.ou_type = t.id) LOOP
462         RETURN QUERY
463         SELECT  ans.depth,
464                 ans.id,
465                 COUNT( cp.id ),
466                 SUM( CASE WHEN cp.status IN (0,7,12) THEN 1 ELSE 0 END ),
467                 COUNT( cp.id ),
468                 trans
469           FROM
470                 actor.org_unit_descendants(ans.id) d
471                 JOIN asset.copy cp ON (cp.circ_lib = d.id)
472                 JOIN asset.call_number cn ON (cn.record = record AND cn.id = cp.call_number)
473           GROUP BY 1,2,6;
474
475         IF NOT FOUND THEN
476             RETURN QUERY SELECT ans.depth, ans.id, 0::BIGINT, 0::BIGINT, 0::BIGINT, trans;
477         END IF;
478
479     END LOOP;
480
481     RETURN;
482 END;
483 $f$ LANGUAGE PLPGSQL;
484
485 CREATE OR REPLACE FUNCTION asset.staff_lasso_record_copy_count (i_lasso INT, record BIGINT) RETURNS TABLE (depth INT, org_unit INT, visible BIGINT, available BIGINT, unshadow BIGINT, transcendant INT) AS $f$
486 DECLARE
487     ans RECORD;
488     trans INT;
489 BEGIN
490     SELECT 1 INTO trans FROM biblio.record_entry b JOIN config.bib_source src ON (b.source = src.id) WHERE src.transcendant AND b.id = record;
491
492     FOR ans IN SELECT u.org_unit AS id FROM actor.org_lasso_map AS u WHERE lasso = i_lasso LOOP
493         RETURN QUERY
494         SELECT  -1,
495                 ans.id,
496                 COUNT( cp.id ),
497                 SUM( CASE WHEN cp.status IN (0,7,12) THEN 1 ELSE 0 END ),
498                 COUNT( cp.id ),
499                 trans
500           FROM
501                 actor.org_unit_descendants(ans.id) d
502                 JOIN asset.copy cp ON (cp.circ_lib = d.id)
503                 JOIN asset.call_number cn ON (cn.record = record AND cn.id = cp.call_number)
504           GROUP BY 1,2,6;
505
506         IF NOT FOUND THEN
507             RETURN QUERY SELECT ans.depth, ans.id, 0::BIGINT, 0::BIGINT, 0::BIGINT, trans;
508         END IF;
509
510     END LOOP;
511
512     RETURN;
513 END;
514 $f$ LANGUAGE PLPGSQL;
515
516 CREATE OR REPLACE FUNCTION asset.record_copy_count ( place INT, record BIGINT, staff BOOL) RETURNS TABLE (depth INT, org_unit INT, visible BIGINT, available BIGINT, unshadow BIGINT, transcendant INT) AS $f$
517 BEGIN
518     IF staff IS TRUE THEN
519         IF place > 0 THEN
520             RETURN QUERY SELECT * FROM asset.staff_ou_record_copy_count( place, record );
521         ELSE
522             RETURN QUERY SELECT * FROM asset.staff_lasso_record_copy_count( -place, record );
523         END IF;
524     ELSE
525         IF place > 0 THEN
526             RETURN QUERY SELECT * FROM asset.opac_ou_record_copy_count( place, record );
527         ELSE
528             RETURN QUERY SELECT * FROM asset.opac_lasso_record_copy_count( -place, record );
529         END IF;
530     END IF;
531
532     RETURN;
533 END;
534 $f$ LANGUAGE PLPGSQL;
535
536 CREATE OR REPLACE FUNCTION asset.opac_ou_metarecord_copy_count (org INT, record BIGINT) RETURNS TABLE (depth INT, org_unit INT, visible BIGINT, available BIGINT, unshadow BIGINT, transcendant INT) AS $f$
537 DECLARE
538     ans RECORD;
539     trans INT;
540 BEGIN
541     SELECT 1 INTO trans FROM biblio.record_entry b JOIN config.bib_source src ON (b.source = src.id) WHERE src.transcendant AND b.id = record;
542
543     FOR ans IN SELECT u.id, t.depth FROM actor.org_unit_ancestors(org) AS u JOIN actor.org_unit_type t ON (u.ou_type = t.id) LOOP
544         RETURN QUERY
545         SELECT  ans.depth,
546                 ans.id,
547                 COUNT( av.id ),
548                 SUM( CASE WHEN cp.status IN (0,7,12) THEN 1 ELSE 0 END ),
549                 COUNT( av.id ),
550                 trans
551           FROM  
552                 actor.org_unit_descendants(ans.id) d
553                 JOIN asset.opac_visible_copies av ON (av.record = record AND av.circ_lib = d.id)
554                 JOIN asset.copy cp ON (cp.id = av.id)
555                 JOIN metabib.metarecord_source_map m ON (m.source = av.record)
556           GROUP BY 1,2,6;
557
558         IF NOT FOUND THEN
559             RETURN QUERY SELECT ans.depth, ans.id, 0::BIGINT, 0::BIGINT, 0::BIGINT, trans;
560         END IF;
561
562     END LOOP;
563
564     RETURN;
565 END;
566 $f$ LANGUAGE PLPGSQL;
567
568 CREATE OR REPLACE FUNCTION asset.opac_lasso_metarecord_copy_count (i_lasso INT, record BIGINT) RETURNS TABLE (depth INT, org_unit INT, visible BIGINT, available BIGINT, unshadow BIGINT, transcendant INT) AS $f$
569 DECLARE
570     ans RECORD;
571     trans INT;
572 BEGIN
573     SELECT 1 INTO trans FROM biblio.record_entry b JOIN config.bib_source src ON (b.source = src.id) WHERE src.transcendant AND b.id = record;
574
575     FOR ans IN SELECT u.org_unit AS id FROM actor.org_lasso_map AS u WHERE lasso = i_lasso LOOP
576         RETURN QUERY
577         SELECT  -1,
578                 ans.id,
579                 COUNT( av.id ),
580                 SUM( CASE WHEN cp.status IN (0,7,12) THEN 1 ELSE 0 END ),
581                 COUNT( av.id ),
582                 trans
583           FROM
584                 actor.org_unit_descendants(ans.id) d
585                 JOIN asset.opac_visible_copies av ON (av.record = record AND av.circ_lib = d.id)
586                 JOIN asset.copy cp ON (cp.id = av.id)
587                 JOIN metabib.metarecord_source_map m ON (m.source = av.record)
588           GROUP BY 1,2,6;
589
590         IF NOT FOUND THEN
591             RETURN QUERY SELECT ans.depth, ans.id, 0::BIGINT, 0::BIGINT, 0::BIGINT, trans;
592         END IF;
593
594     END LOOP;   
595                 
596     RETURN;     
597 END;            
598 $f$ LANGUAGE PLPGSQL;
599
600 CREATE OR REPLACE FUNCTION asset.staff_ou_metarecord_copy_count (org INT, record BIGINT) RETURNS TABLE (depth INT, org_unit INT, visible BIGINT, available BIGINT, unshadow BIGINT, transcendant INT) AS $f$
601 DECLARE         
602     ans RECORD; 
603     trans INT;
604 BEGIN
605     SELECT 1 INTO trans FROM biblio.record_entry b JOIN config.bib_source src ON (b.source = src.id) WHERE src.transcendant AND b.id = record;
606
607     FOR ans IN SELECT u.id, t.depth FROM actor.org_unit_ancestors(org) AS u JOIN actor.org_unit_type t ON (u.ou_type = t.id) LOOP
608         RETURN QUERY
609         SELECT  ans.depth,
610                 ans.id,
611                 COUNT( cp.id ),
612                 SUM( CASE WHEN cp.status IN (0,7,12) THEN 1 ELSE 0 END ),
613                 COUNT( cp.id ),
614                 trans
615           FROM
616                 actor.org_unit_descendants(ans.id) d
617                 JOIN asset.copy cp ON (cp.circ_lib = d.id)
618                 JOIN asset.call_number cn ON (cn.record = record AND cn.id = cp.call_number)
619                 JOIN metabib.metarecord_source_map m ON (m.source = cn.record)
620           GROUP BY 1,2,6;
621
622         IF NOT FOUND THEN
623             RETURN QUERY SELECT ans.depth, ans.id, 0::BIGINT, 0::BIGINT, 0::BIGINT, trans;
624         END IF;
625
626     END LOOP;
627
628     RETURN;
629 END;
630 $f$ LANGUAGE PLPGSQL;
631
632 CREATE OR REPLACE FUNCTION asset.staff_lasso_metarecord_copy_count (i_lasso INT, record BIGINT) RETURNS TABLE (depth INT, org_unit INT, visible BIGINT, available BIGINT, unshadow BIGINT, transcendant INT) AS $f$
633 DECLARE
634     ans RECORD;
635     trans INT;
636 BEGIN
637     SELECT 1 INTO trans FROM biblio.record_entry b JOIN config.bib_source src ON (b.source = src.id) WHERE src.transcendant AND b.id = record;
638
639     FOR ans IN SELECT u.org_unit AS id FROM actor.org_lasso_map AS u WHERE lasso = i_lasso LOOP
640         RETURN QUERY
641         SELECT  -1,
642                 ans.id,
643                 COUNT( cp.id ),
644                 SUM( CASE WHEN cp.status IN (0,7,12) THEN 1 ELSE 0 END ),
645                 COUNT( cp.id ),
646                 trans
647           FROM
648                 actor.org_unit_descendants(ans.id) d
649                 JOIN asset.copy cp ON (cp.circ_lib = d.id)
650                 JOIN asset.call_number cn ON (cn.record = record AND cn.id = cp.call_number)
651                 JOIN metabib.metarecord_source_map m ON (m.source = cn.record)
652           GROUP BY 1,2,6;
653
654         IF NOT FOUND THEN
655             RETURN QUERY SELECT ans.depth, ans.id, 0::BIGINT, 0::BIGINT, 0::BIGINT, trans;
656         END IF;
657
658     END LOOP;
659
660     RETURN;
661 END;
662 $f$ LANGUAGE PLPGSQL;
663
664 CREATE OR REPLACE FUNCTION asset.metarecord_copy_count ( place INT, record BIGINT, staff BOOL) RETURNS TABLE (depth INT, org_unit INT, visible BIGINT, available BIGINT, unshadow BIGINT, transcendant INT) AS $f$
665 BEGIN
666     IF staff IS TRUE THEN
667         IF place > 0 THEN
668             RETURN QUERY SELECT * FROM asset.staff_ou_metarecord_copy_count( place, record );
669         ELSE
670             RETURN QUERY SELECT * FROM asset.staff_lasso_metarecord_copy_count( -place, record );
671         END IF;
672     ELSE
673         IF place > 0 THEN
674             RETURN QUERY SELECT * FROM asset.opac_ou_metarecord_copy_count( place, record );
675         ELSE
676             RETURN QUERY SELECT * FROM asset.opac_lasso_metarecord_copy_count( -place, record );
677         END IF;
678     END IF;
679
680     RETURN;
681 END;
682 $f$ LANGUAGE PLPGSQL;
683
684 COMMIT;
685