]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/sql/Pg/002.schema.config.sql
Add an index on asset.copy(create_date) for item-age browse
[working/Evergreen.git] / Open-ILS / src / sql / Pg / 002.schema.config.sql
1 /*
2  * Copyright (C) 2004-2008  Georgia Public Library Service
3  * Copyright (C) 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
19
20 DROP SCHEMA IF EXISTS stats CASCADE;
21 DROP SCHEMA IF EXISTS config CASCADE;
22
23 BEGIN;
24 CREATE SCHEMA stats;
25
26 CREATE SCHEMA config;
27 COMMENT ON SCHEMA config IS $$
28 /*
29  * Copyright (C) 2005  Georgia Public Library Service 
30  * Mike Rylander <mrylander@gmail.com>
31  *
32  * The config schema holds static configuration data for the
33  * Open-ILS installation.
34  *
35  * ****
36  *
37  * This program is free software; you can redistribute it and/or
38  * modify it under the terms of the GNU General Public License
39  * as published by the Free Software Foundation; either version 2
40  * of the License, or (at your option) any later version.
41  *
42  * This program is distributed in the hope that it will be useful,
43  * but WITHOUT ANY WARRANTY; without even the implied warranty of
44  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
45  * GNU General Public License for more details.
46  */
47 $$;
48
49 CREATE TABLE config.internal_flag (
50     name    TEXT    PRIMARY KEY,
51     value   TEXT,
52     enabled BOOL    NOT NULL DEFAULT FALSE
53 );
54 INSERT INTO config.internal_flag (name) VALUES ('ingest.metarecord_mapping.skip_on_insert');
55 INSERT INTO config.internal_flag (name) VALUES ('ingest.metarecord_mapping.skip_on_update');
56 INSERT INTO config.internal_flag (name) VALUES ('ingest.reingest.force_on_same_marc');
57 INSERT INTO config.internal_flag (name) VALUES ('ingest.disable_located_uri');
58 INSERT INTO config.internal_flag (name) VALUES ('ingest.disable_metabib_full_rec');
59 INSERT INTO config.internal_flag (name) VALUES ('ingest.disable_metabib_rec_descriptor');
60 INSERT INTO config.internal_flag (name) VALUES ('ingest.disable_metabib_field_entry');
61 INSERT INTO config.internal_flag (name) VALUES ('ingest.assume_inserts_only');
62
63 CREATE TABLE config.global_flag (
64     label   TEXT    NOT NULL
65 ) INHERITS (config.internal_flag);
66 ALTER TABLE config.global_flag ADD PRIMARY KEY (name);
67
68 CREATE TABLE config.upgrade_log (
69     version         TEXT    PRIMARY KEY,
70     install_date    TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
71 );
72
73 INSERT INTO config.upgrade_log (version) VALUES ('0466'); -- dbs
74
75 CREATE TABLE config.bib_source (
76         id              SERIAL  PRIMARY KEY,
77         quality         INT     CHECK ( quality BETWEEN 0 AND 100 ),
78         source          TEXT    NOT NULL UNIQUE,
79         transcendant    BOOL    NOT NULL DEFAULT FALSE
80 );
81 COMMENT ON TABLE config.bib_source IS $$
82 /*
83  * Copyright (C) 2005  Georgia Public Library Service 
84  * Mike Rylander <mrylander@gmail.com>
85  *
86  * Valid sources of MARC records
87  *
88  * This is table is used to set up the relative "quality" of each
89  * MARC source, such as OCLC.
90  *
91  * ****
92  *
93  * This program is free software; you can redistribute it and/or
94  * modify it under the terms of the GNU General Public License
95  * as published by the Free Software Foundation; either version 2
96  * of the License, or (at your option) any later version.
97  *
98  * This program is distributed in the hope that it will be useful,
99  * but WITHOUT ANY WARRANTY; without even the implied warranty of
100  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
101  * GNU General Public License for more details.
102  */
103 $$;
104
105 CREATE TABLE config.standing (
106         id              SERIAL  PRIMARY KEY,
107         value           TEXT    NOT NULL UNIQUE
108 );
109 COMMENT ON TABLE config.standing IS $$
110 /*
111  * Copyright (C) 2005  Georgia Public Library Service 
112  * Mike Rylander <mrylander@gmail.com>
113  *
114  * Patron Standings
115  *
116  * This table contains the values that can be applied to a patron
117  * by a staff member.  These values should not be changed, other
118  * than for translation, as the ID column is currently a "magic
119  * number" in the source. :(
120  *
121  * ****
122  *
123  * This program is free software; you can redistribute it and/or
124  * modify it under the terms of the GNU General Public License
125  * as published by the Free Software Foundation; either version 2
126  * of the License, or (at your option) any later version.
127  *
128  * This program is distributed in the hope that it will be useful,
129  * but WITHOUT ANY WARRANTY; without even the implied warranty of
130  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
131  * GNU General Public License for more details.
132  */
133 $$;
134
135 CREATE TABLE config.standing_penalty (
136         id                      SERIAL  PRIMARY KEY,
137         name            TEXT    NOT NULL UNIQUE,
138         label           TEXT    NOT NULL,
139         block_list      TEXT,
140         org_depth       INTEGER
141 );
142 INSERT INTO config.standing_penalty (id,name,label,block_list)
143         VALUES (1,'PATRON_EXCEEDS_FINES','Patron exceeds fine threshold','CIRC|HOLD|RENEW');
144 INSERT INTO config.standing_penalty (id,name,label,block_list)
145         VALUES (2,'PATRON_EXCEEDS_OVERDUE_COUNT','Patron exceeds max overdue item threshold','CIRC|HOLD|RENEW');
146 INSERT INTO config.standing_penalty (id,name,label,block_list)
147         VALUES (3,'PATRON_EXCEEDS_CHECKOUT_COUNT','Patron exceeds max checked out item threshold','CIRC');
148 INSERT INTO config.standing_penalty (id,name,label,block_list)
149         VALUES (4,'PATRON_EXCEEDS_COLLECTIONS_WARNING','Patron exceeds pre-collections warning fine threshold','CIRC|HOLD|RENEW');
150
151 INSERT INTO config.standing_penalty (id,name,label) VALUES (20,'ALERT_NOTE','Alerting Note, no blocks');
152 INSERT INTO config.standing_penalty (id,name,label) VALUES (21,'SILENT_NOTE','Note, no blocks');
153 INSERT INTO config.standing_penalty (id,name,label,block_list) VALUES (22,'STAFF_C','Alerting block on Circ','CIRC');
154 INSERT INTO config.standing_penalty (id,name,label,block_list) VALUES (23,'STAFF_CH','Alerting block on Circ and Hold','CIRC|HOLD');
155 INSERT INTO config.standing_penalty (id,name,label,block_list) VALUES (24,'STAFF_CR','Alerting block on Circ and Renew','CIRC|RENEW');
156 INSERT INTO config.standing_penalty (id,name,label,block_list) VALUES (25,'STAFF_CHR','Alerting block on Circ, Hold and Renew','CIRC|HOLD|RENEW');
157 INSERT INTO config.standing_penalty (id,name,label,block_list) VALUES (26,'STAFF_HR','Alerting block on Hold and Renew','HOLD|RENEW');
158 INSERT INTO config.standing_penalty (id,name,label,block_list) VALUES (27,'STAFF_H','Alerting block on Hold','HOLD');
159 INSERT INTO config.standing_penalty (id,name,label,block_list) VALUES (28,'STAFF_R','Alerting block on Renew','RENEW');
160 INSERT INTO config.standing_penalty (id,name,label) VALUES (29,'INVALID_PATRON_ADDRESS','Patron has an invalid address');
161 INSERT INTO config.standing_penalty (id,name,label) VALUES (30,'PATRON_IN_COLLECTIONS','Patron has been referred to a collections agency');
162
163 SELECT SETVAL('config.standing_penalty_id_seq', 100);
164
165 CREATE TABLE config.xml_transform (
166         name            TEXT    PRIMARY KEY,
167         namespace_uri   TEXT    NOT NULL,
168         prefix          TEXT    NOT NULL,
169         xslt            TEXT    NOT NULL
170 );
171
172 CREATE TABLE config.biblio_fingerprint (
173         id                      SERIAL  PRIMARY KEY,
174         name            TEXT    NOT NULL, 
175         xpath           TEXT    NOT NULL,
176     first_word  BOOL    NOT NULL DEFAULT FALSE,
177         format          TEXT    NOT NULL DEFAULT 'marcxml'
178 );
179
180 INSERT INTO config.biblio_fingerprint (name, xpath, format)
181     VALUES (
182         'Title',
183         '//marc:datafield[@tag="700"]/marc:subfield[@code="t"]|' ||
184             '//marc:datafield[@tag="240"]/marc:subfield[@code="a"]|' ||
185             '//marc:datafield[@tag="242"]/marc:subfield[@code="a"]|' ||
186             '//marc:datafield[@tag="246"]/marc:subfield[@code="a"]|' ||
187             '//marc:datafield[@tag="245"]/marc:subfield[@code="a"]',
188         'marcxml'
189     );
190
191 INSERT INTO config.biblio_fingerprint (name, xpath, format, first_word)
192     VALUES (
193         'Author',
194         '//marc:datafield[@tag="700" and ./*[@code="t"]]/marc:subfield[@code="a"]|'
195             '//marc:datafield[@tag="100"]/marc:subfield[@code="a"]|'
196             '//marc:datafield[@tag="110"]/marc:subfield[@code="a"]|'
197             '//marc:datafield[@tag="111"]/marc:subfield[@code="a"]|'
198             '//marc:datafield[@tag="260"]/marc:subfield[@code="b"]',
199         'marcxml',
200         TRUE
201     );
202
203 CREATE TABLE config.metabib_class (
204     name    TEXT    PRIMARY KEY,
205     label   TEXT    NOT NULL UNIQUE
206 );
207
208 CREATE TABLE config.metabib_field (
209         id              SERIAL  PRIMARY KEY,
210         field_class     TEXT    NOT NULL REFERENCES config.metabib_class (name),
211         name            TEXT    NOT NULL,
212         label           TEXT    NOT NULL,
213         xpath           TEXT    NOT NULL,
214         weight          INT     NOT NULL DEFAULT 1,
215         format          TEXT    NOT NULL REFERENCES config.xml_transform (name) DEFAULT 'mods33',
216         search_field    BOOL    NOT NULL DEFAULT TRUE,
217         facet_field     BOOL    NOT NULL DEFAULT FALSE,
218     facet_xpath TEXT
219 );
220 COMMENT ON TABLE config.metabib_field IS $$
221 /*
222  * Copyright (C) 2005  Georgia Public Library Service 
223  * Mike Rylander <mrylander@gmail.com>
224  *
225  * XPath used for record indexing ingest
226  *
227  * This table contains the XPath used to chop up MODS into its
228  * indexable parts.  Each XPath entry is named and assigned to
229  * a "class" of either title, subject, author, keyword or series.
230  * 
231  *
232  * ****
233  *
234  * This program is free software; you can redistribute it and/or
235  * modify it under the terms of the GNU General Public License
236  * as published by the Free Software Foundation; either version 2
237  * of the License, or (at your option) any later version.
238  *
239  * This program is distributed in the hope that it will be useful,
240  * but WITHOUT ANY WARRANTY; without even the implied warranty of
241  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
242  * GNU General Public License for more details.
243  */
244 $$;
245
246 CREATE UNIQUE INDEX config_metabib_field_class_name_idx ON config.metabib_field (field_class, name);
247
248 CREATE TABLE config.metabib_search_alias (
249     alias       TEXT    PRIMARY KEY,
250     field_class TEXT    NOT NULL REFERENCES config.metabib_class (name),
251     field       INT     REFERENCES config.metabib_field (id)
252 );
253
254 CREATE TABLE config.non_cataloged_type (
255         id              SERIAL          PRIMARY KEY,
256         owning_lib      INT             NOT NULL, -- REFERENCES actor.org_unit (id),
257         name            TEXT            NOT NULL,
258         circ_duration   INTERVAL        NOT NULL DEFAULT '14 days'::INTERVAL,
259         in_house        BOOL            NOT NULL DEFAULT FALSE,
260         CONSTRAINT noncat_once_per_lib UNIQUE (owning_lib,name)
261 );
262 COMMENT ON TABLE config.non_cataloged_type IS $$
263 /*
264  * Copyright (C) 2005  Georgia Public Library Service 
265  * Mike Rylander <mrylander@gmail.com>
266  *
267  * Types of valid non-cataloged items.
268  *
269  *
270  * ****
271  *
272  * This program is free software; you can redistribute it and/or
273  * modify it under the terms of the GNU General Public License
274  * as published by the Free Software Foundation; either version 2
275  * of the License, or (at your option) any later version.
276  *
277  * This program is distributed in the hope that it will be useful,
278  * but WITHOUT ANY WARRANTY; without even the implied warranty of
279  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
280  * GNU General Public License for more details.
281  */
282 $$;
283
284 CREATE TABLE config.identification_type (
285         id              SERIAL  PRIMARY KEY,
286         name            TEXT    NOT NULL UNIQUE
287 );
288 COMMENT ON TABLE config.identification_type IS $$
289 /*
290  * Copyright (C) 2005  Georgia Public Library Service 
291  * Mike Rylander <mrylander@gmail.com>
292  *
293  * Types of valid patron identification.
294  *
295  * Each patron must display at least one valid form of identification
296  * in order to get a library card.  This table lists those forms.
297  * 
298  *
299  * ****
300  *
301  * This program is free software; you can redistribute it and/or
302  * modify it under the terms of the GNU General Public License
303  * as published by the Free Software Foundation; either version 2
304  * of the License, or (at your option) any later version.
305  *
306  * This program is distributed in the hope that it will be useful,
307  * but WITHOUT ANY WARRANTY; without even the implied warranty of
308  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
309  * GNU General Public License for more details.
310  */
311 $$;
312
313 CREATE TABLE config.rule_circ_duration (
314         id              SERIAL          PRIMARY KEY,
315         name            TEXT            NOT NULL UNIQUE CHECK ( name ~ E'^\\w+$' ),
316         extended        INTERVAL        NOT NULL,
317         normal          INTERVAL        NOT NULL,
318         shrt            INTERVAL        NOT NULL,
319         max_renewals    INT             NOT NULL
320 );
321 COMMENT ON TABLE config.rule_circ_duration IS $$
322 /*
323  * Copyright (C) 2005  Georgia Public Library Service 
324  * Mike Rylander <mrylander@gmail.com>
325  *
326  * Circulation Duration rules
327  *
328  * Each circulation is given a duration based on one of these rules.
329  * 
330  *
331  * ****
332  *
333  * This program is free software; you can redistribute it and/or
334  * modify it under the terms of the GNU General Public License
335  * as published by the Free Software Foundation; either version 2
336  * of the License, or (at your option) any later version.
337  *
338  * This program is distributed in the hope that it will be useful,
339  * but WITHOUT ANY WARRANTY; without even the implied warranty of
340  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
341  * GNU General Public License for more details.
342  */
343 $$;
344
345 CREATE TABLE config.hard_due_date (
346     id                  SERIAL      PRIMARY KEY,
347     name                TEXT        NOT NULL UNIQUE CHECK ( name ~ E'^\\w+$' ),
348     ceiling_date        TIMESTAMPTZ NOT NULL,
349     forceto             BOOL        NOT NULL,
350     owner               INT         NOT NULL   -- REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED,
351 );
352
353 CREATE TABLE config.hard_due_date_values (
354     id                  SERIAL      PRIMARY KEY,
355     hard_due_date       INT         NOT NULL REFERENCES config.hard_due_date (id)
356                                     DEFERRABLE INITIALLY DEFERRED,
357     ceiling_date        TIMESTAMPTZ NOT NULL,
358     active_date         TIMESTAMPTZ NOT NULL
359 );
360
361
362 CREATE OR REPLACE FUNCTION config.update_hard_due_dates () RETURNS INT AS $func$
363 DECLARE
364     temp_value  config.hard_due_date_values%ROWTYPE;
365     updated     INT := 0;
366 BEGIN
367     FOR temp_value IN
368       SELECT  DISTINCT ON (hard_due_date) *
369         FROM  config.hard_due_date_values
370         WHERE active_date <= NOW() -- We've passed (or are at) the rollover time
371         ORDER BY active_date DESC -- Latest (nearest to us) active time
372    LOOP
373         UPDATE  config.hard_due_date
374           SET   ceiling_date = temp_value.ceiling_date
375           WHERE id = temp_value.hard_due_date
376                 AND ceiling_date <> temp_value.ceiling_date; -- Time is equal if we've already updated the chdd
377
378         IF FOUND THEN
379             updated := updated + 1;
380         END IF;
381     END LOOP;
382
383     RETURN updated;
384 END;
385 $func$ LANGUAGE plpgsql;
386
387 CREATE TABLE config.rule_max_fine (
388     id          SERIAL          PRIMARY KEY,
389     name        TEXT            NOT NULL UNIQUE CHECK ( name ~ E'^\\w+$' ),
390     amount      NUMERIC(6,2)    NOT NULL,
391     is_percent  BOOL            NOT NULL DEFAULT FALSE
392 );
393 COMMENT ON TABLE config.rule_max_fine IS $$
394 /*
395  * Copyright (C) 2005  Georgia Public Library Service 
396  * Mike Rylander <mrylander@gmail.com>
397  *
398  * Circulation Max Fine rules
399  *
400  * Each circulation is given a maximum fine based on one of
401  * these rules.
402  * 
403  *
404  * ****
405  *
406  * This program is free software; you can redistribute it and/or
407  * modify it under the terms of the GNU General Public License
408  * as published by the Free Software Foundation; either version 2
409  * of the License, or (at your option) any later version.
410  *
411  * This program is distributed in the hope that it will be useful,
412  * but WITHOUT ANY WARRANTY; without even the implied warranty of
413  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
414  * GNU General Public License for more details.
415  */
416 $$;
417
418 CREATE TABLE config.rule_recurring_fine (
419         id                      SERIAL          PRIMARY KEY,
420         name                    TEXT            NOT NULL UNIQUE CHECK ( name ~ E'^\\w+$' ),
421         high                    NUMERIC(6,2)    NOT NULL,
422         normal                  NUMERIC(6,2)    NOT NULL,
423         low                     NUMERIC(6,2)    NOT NULL,
424         recurrence_interval     INTERVAL        NOT NULL DEFAULT '1 day'::INTERVAL
425 );
426 COMMENT ON TABLE config.rule_recurring_fine IS $$
427 /*
428  * Copyright (C) 2005  Georgia Public Library Service 
429  * Mike Rylander <mrylander@gmail.com>
430  *
431  * Circulation Recurring Fine rules
432  *
433  * Each circulation is given a recurring fine amount based on one of
434  * these rules.  The recurrence_interval should not be any shorter
435  * than the interval between runs of the fine_processor.pl script
436  * (which is run from CRON), or you could miss fines.
437  * 
438  *
439  * ****
440  *
441  * This program is free software; you can redistribute it and/or
442  * modify it under the terms of the GNU General Public License
443  * as published by the Free Software Foundation; either version 2
444  * of the License, or (at your option) any later version.
445  *
446  * This program is distributed in the hope that it will be useful,
447  * but WITHOUT ANY WARRANTY; without even the implied warranty of
448  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
449  * GNU General Public License for more details.
450  */
451 $$;
452
453
454 CREATE TABLE config.rule_age_hold_protect (
455         id      SERIAL          PRIMARY KEY,
456         name    TEXT            NOT NULL UNIQUE CHECK ( name ~ E'^\\w+$' ),
457         age     INTERVAL        NOT NULL,
458         prox    INT             NOT NULL
459 );
460 COMMENT ON TABLE config.rule_age_hold_protect IS $$
461 /*
462  * Copyright (C) 2005  Georgia Public Library Service 
463  * Mike Rylander <mrylander@gmail.com>
464  *
465  * Hold Item Age Protection rules
466  *
467  * A hold request can only capture new(ish) items when they are
468  * within a particular proximity of the home_ou of the requesting
469  * user.  The proximity ('prox' column) is calculated by counting
470  * the number of tree edges between the user's home_ou and the owning_lib
471  * of the copy that could fulfill the hold.
472  * 
473  *
474  * ****
475  *
476  * This program is free software; you can redistribute it and/or
477  * modify it under the terms of the GNU General Public License
478  * as published by the Free Software Foundation; either version 2
479  * of the License, or (at your option) any later version.
480  *
481  * This program is distributed in the hope that it will be useful,
482  * but WITHOUT ANY WARRANTY; without even the implied warranty of
483  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
484  * GNU General Public License for more details.
485  */
486 $$;
487
488 CREATE TABLE config.copy_status (
489         id              SERIAL  PRIMARY KEY,
490         name            TEXT    NOT NULL UNIQUE,
491         holdable        BOOL    NOT NULL DEFAULT FALSE,
492         opac_visible    BOOL    NOT NULL DEFAULT FALSE
493 );
494 COMMENT ON TABLE config.copy_status IS $$
495 /*
496  * Copyright (C) 2005  Georgia Public Library Service 
497  * Mike Rylander <mrylander@gmail.com>
498  *
499  * Copy Statuses
500  *
501  * The available copy statuses, and whether a copy in that
502  * status is available for hold request capture.  0 (zero) is
503  * the only special number in this set, meaning that the item
504  * is available for immediate checkout, and is counted as available
505  * in the OPAC.
506  *
507  * Statuses with an ID below 100 are not removable, and have special
508  * meaning in the code.  Do not change them except to translate the
509  * textual name.
510  *
511  * You may add and remove statuses above 100, and these can be used
512  * to remove items from normal circulation without affecting the rest
513  * of the copy's values or its location.
514  *
515  * ****
516  *
517  * This program is free software; you can redistribute it and/or
518  * modify it under the terms of the GNU General Public License
519  * as published by the Free Software Foundation; either version 2
520  * of the License, or (at your option) any later version.
521  *
522  * This program is distributed in the hope that it will be useful,
523  * but WITHOUT ANY WARRANTY; without even the implied warranty of
524  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
525  * GNU General Public License for more details.
526  */
527 $$;
528
529 CREATE TABLE config.net_access_level (
530         id      SERIAL          PRIMARY KEY,
531         name    TEXT            NOT NULL UNIQUE
532 );
533 COMMENT ON TABLE config.net_access_level IS $$
534 /*
535  * Copyright (C) 2005  Georgia Public Library Service 
536  * Mike Rylander <mrylander@gmail.com>
537  *
538  * Patron Network Access level
539  *
540  * This will be used to inform the in-library firewall of how much
541  * internet access the using patron should be allowed.
542  *
543  * ****
544  *
545  * This program is free software; you can redistribute it and/or
546  * modify it under the terms of the GNU General Public License
547  * as published by the Free Software Foundation; either version 2
548  * of the License, or (at your option) any later version.
549  *
550  * This program is distributed in the hope that it will be useful,
551  * but WITHOUT ANY WARRANTY; without even the implied warranty of
552  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
553  * GNU General Public License for more details.
554  */
555 $$;
556
557
558 CREATE TABLE config.remote_account (
559     id          SERIAL  PRIMARY KEY,
560     label       TEXT    NOT NULL,
561     host        TEXT    NOT NULL,   -- name or IP, :port optional
562     username    TEXT,               -- optional, since we could default to $USER
563     password    TEXT,               -- optional, since we could use SSH keys, or anonymous login.
564     account     TEXT,               -- aka profile or FTP "account" command
565     path        TEXT,               -- aka directory
566     owner       INT     NOT NULL,   -- REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED,
567     last_activity TIMESTAMP WITH TIME ZONE
568 );
569
570 CREATE TABLE config.audience_map (
571         code            TEXT    PRIMARY KEY,
572         value           TEXT    NOT NULL,
573         description     TEXT
574 );
575
576 CREATE TABLE config.lit_form_map (
577         code            TEXT    PRIMARY KEY,
578         value           TEXT    NOT NULL,
579         description     TEXT
580 );
581
582 CREATE TABLE config.language_map (
583         code    TEXT    PRIMARY KEY,
584         value   TEXT    NOT NULL
585 );
586
587 CREATE TABLE config.item_form_map (
588         code    TEXT    PRIMARY KEY,
589         value   TEXT    NOT NULL
590 );
591
592 CREATE TABLE config.item_type_map (
593         code    TEXT    PRIMARY KEY,
594         value   TEXT    NOT NULL
595 );
596
597 CREATE TABLE config.bib_level_map (
598         code    TEXT    PRIMARY KEY,
599         value   TEXT    NOT NULL
600 );
601
602 CREATE TABLE config.marc21_rec_type_map (
603     code        TEXT    PRIMARY KEY,
604     type_val    TEXT    NOT NULL,
605     blvl_val    TEXT    NOT NULL
606 );
607
608 CREATE TABLE config.marc21_ff_pos_map (
609     id          SERIAL  PRIMARY KEY,
610     fixed_field TEXT    NOT NULL,
611     tag         TEXT    NOT NULL,
612     rec_type    TEXT    NOT NULL,
613     start_pos   INT     NOT NULL,
614     length      INT     NOT NULL,
615     default_val TEXT    NOT NULL DEFAULT ' '
616 );
617
618 CREATE TABLE config.marc21_physical_characteristic_type_map (
619     ptype_key   TEXT    PRIMARY KEY,
620     label       TEXT    NOT NULL -- I18N
621 );
622
623 CREATE TABLE config.marc21_physical_characteristic_subfield_map (
624     id          SERIAL  PRIMARY KEY,
625     ptype_key   TEXT    NOT NULL REFERENCES config.marc21_physical_characteristic_type_map (ptype_key) ON DELETE CASCADE ON UPDATE CASCADE,
626     subfield    TEXT    NOT NULL,
627     start_pos   INT     NOT NULL,
628     length      INT     NOT NULL,
629     label       TEXT    NOT NULL -- I18N
630 );
631
632 CREATE TABLE config.marc21_physical_characteristic_value_map (
633     id              SERIAL  PRIMARY KEY,
634     value           TEXT    NOT NULL,
635     ptype_subfield  INT     NOT NULL REFERENCES config.marc21_physical_characteristic_subfield_map (id),
636     label           TEXT    NOT NULL -- I18N
637 );
638
639
640 CREATE TABLE config.z3950_source (
641     name                TEXT    PRIMARY KEY,
642     label               TEXT    NOT NULL UNIQUE,
643     host                TEXT    NOT NULL,
644     port                INT     NOT NULL,
645     db                  TEXT    NOT NULL,
646     record_format       TEXT    NOT NULL DEFAULT 'FI',
647     transmission_format TEXT    NOT NULL DEFAULT 'usmarc',
648     auth                BOOL    NOT NULL DEFAULT TRUE
649 );
650
651 COMMENT ON TABLE config.z3950_source IS $$
652 Z39.50 Sources
653
654 Each row in this table represents a database searchable via Z39.50.
655 $$;
656
657 COMMENT ON COLUMN config.z3950_source.record_format IS $$
658 Z39.50 element set.
659 $$;
660
661 COMMENT ON COLUMN config.z3950_source.transmission_format IS $$
662 Z39.50 preferred record syntax..
663 $$;
664
665
666 CREATE TABLE config.z3950_attr (
667     id          SERIAL  PRIMARY KEY,
668     source      TEXT    NOT NULL REFERENCES config.z3950_source (name) DEFERRABLE INITIALLY DEFERRED,
669     name        TEXT    NOT NULL,
670     label       TEXT    NOT NULL,
671     code        INT     NOT NULL,
672     format      INT     NOT NULL,
673     truncation  INT     NOT NULL DEFAULT 0,
674     CONSTRAINT z_code_format_once_per_source UNIQUE (code,format,source)
675 );
676
677 CREATE TABLE config.i18n_locale (
678     code        TEXT    PRIMARY KEY,
679     marc_code   TEXT    NOT NULL REFERENCES config.language_map (code) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
680     name        TEXT    UNIQUE NOT NULL,
681     description TEXT
682 );
683
684 CREATE TABLE config.i18n_core (
685     id              BIGSERIAL   PRIMARY KEY,
686     fq_field        TEXT        NOT NULL,
687     identity_value  TEXT        NOT NULL,
688     translation     TEXT        NOT NULL    REFERENCES config.i18n_locale (code) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
689     string          TEXT        NOT NULL
690 );
691
692 CREATE UNIQUE INDEX i18n_identity ON config.i18n_core (fq_field,identity_value,translation);
693
694 CREATE OR REPLACE FUNCTION oils_i18n_update_apply(old_ident TEXT, new_ident TEXT, hint TEXT) RETURNS VOID AS $_$
695 BEGIN
696
697     EXECUTE $$
698         UPDATE  config.i18n_core
699           SET   identity_value = $$ || quote_literal(new_ident) || $$ 
700           WHERE fq_field LIKE '$$ || hint || $$.%' 
701                 AND identity_value = $$ || quote_literal(old_ident) || $$::TEXT;$$;
702
703     RETURN;
704
705 END;
706 $_$ LANGUAGE PLPGSQL;
707
708 CREATE OR REPLACE FUNCTION oils_i18n_id_tracking(/* hint */) RETURNS TRIGGER AS $_$
709 BEGIN
710     PERFORM oils_i18n_update_apply( OLD.id::TEXT, NEW.id::TEXT, TG_ARGV[0]::TEXT );
711     RETURN NEW;
712 END;
713 $_$ LANGUAGE PLPGSQL;
714
715 CREATE OR REPLACE FUNCTION oils_i18n_code_tracking(/* hint */) RETURNS TRIGGER AS $_$
716 BEGIN
717     PERFORM oils_i18n_update_apply( OLD.code::TEXT, NEW.code::TEXT, TG_ARGV[0]::TEXT );
718     RETURN NEW;
719 END;
720 $_$ LANGUAGE PLPGSQL;
721
722 CREATE TABLE config.billing_type (
723     id              SERIAL  PRIMARY KEY,
724     name            TEXT    NOT NULL,
725     owner           INT     NOT NULL, -- REFERENCES actor.org_unit (id)
726     default_price   NUMERIC(6,2),
727     CONSTRAINT billing_type_once_per_lib UNIQUE (name, owner)
728 );
729
730 CREATE TABLE config.settings_group (
731     name    TEXT PRIMARY KEY,
732     label   TEXT UNIQUE NOT NULL -- I18N
733 );
734
735 CREATE TABLE config.org_unit_setting_type (
736     name            TEXT    PRIMARY KEY,
737     label           TEXT    UNIQUE NOT NULL,
738     grp             TEXT    REFERENCES config.settings_group (name),
739     description     TEXT,
740     datatype        TEXT    NOT NULL DEFAULT 'string',
741     fm_class        TEXT,
742     view_perm       INT,
743     update_perm     INT,
744     --
745     -- define valid datatypes
746     --
747     CONSTRAINT coust_valid_datatype CHECK ( datatype IN
748     ( 'bool', 'integer', 'float', 'currency', 'interval',
749       'date', 'string', 'object', 'array', 'link' ) ),
750     --
751     -- fm_class is meaningful only for 'link' datatype
752     --
753     CONSTRAINT coust_no_empty_link CHECK
754     ( ( datatype =  'link' AND fm_class IS NOT NULL ) OR
755       ( datatype <> 'link' AND fm_class IS NULL ) )
756 );
757
758 CREATE TABLE config.usr_setting_type (
759
760     name TEXT PRIMARY KEY,
761     opac_visible BOOL NOT NULL DEFAULT FALSE,
762     label TEXT UNIQUE NOT NULL,
763     description TEXT,
764     grp             TEXT    REFERENCES config.settings_group (name),
765     datatype TEXT NOT NULL DEFAULT 'string',
766     fm_class TEXT,
767
768     --
769     -- define valid datatypes
770     --
771     CONSTRAINT coust_valid_datatype CHECK ( datatype IN
772     ( 'bool', 'integer', 'float', 'currency', 'interval',
773         'date', 'string', 'object', 'array', 'link' ) ),
774
775     --
776     -- fm_class is meaningful only for 'link' datatype
777     --
778     CONSTRAINT coust_no_empty_link CHECK
779     ( ( datatype = 'link' AND fm_class IS NOT NULL ) OR
780         ( datatype <> 'link' AND fm_class IS NULL ) )
781
782 );
783
784 -- Some handy functions, based on existing ones, to provide optional ingest normalization
785
786 CREATE OR REPLACE FUNCTION public.left_trunc( TEXT, INT ) RETURNS TEXT AS $func$
787         SELECT SUBSTRING($1,$2);
788 $func$ LANGUAGE SQL STRICT IMMUTABLE;
789
790 CREATE OR REPLACE FUNCTION public.right_trunc( TEXT, INT ) RETURNS TEXT AS $func$
791         SELECT SUBSTRING($1,1,$2);
792 $func$ LANGUAGE SQL STRICT IMMUTABLE;
793
794 CREATE OR REPLACE FUNCTION public.split_date_range( TEXT ) RETURNS TEXT AS $func$
795         SELECT REGEXP_REPLACE( $1, E'(\\d{4})-(\\d{4})', E'\\1 \\2', 'g' );
796 $func$ LANGUAGE SQL STRICT IMMUTABLE;
797
798 CREATE OR REPLACE FUNCTION public.translate_isbn1013( TEXT ) RETURNS TEXT AS $func$
799     use Business::ISBN;
800     use strict;
801     use warnings;
802
803     # For each ISBN found in a single string containing a set of ISBNs:
804     #   * Normalize an incoming ISBN to have the correct checksum and no hyphens
805     #   * Convert an incoming ISBN10 or ISBN13 to its counterpart and return
806
807     my $input = shift;
808     my $output = '';
809
810     foreach my $word (split(/\s/, $input)) {
811         my $isbn = Business::ISBN->new($word);
812
813         # First check the checksum; if it is not valid, fix it and add the original
814         # bad-checksum ISBN to the output
815         if ($isbn && $isbn->is_valid_checksum() == Business::ISBN::BAD_CHECKSUM) {
816             $output .= $isbn->isbn() . " ";
817             $isbn->fix_checksum();
818         }
819
820         # If we now have a valid ISBN, convert it to its counterpart ISBN10/ISBN13
821         # and add the normalized original ISBN to the output
822         if ($isbn && $isbn->is_valid()) {
823             my $isbn_xlated = ($isbn->type eq "ISBN13") ? $isbn->as_isbn10 : $isbn->as_isbn13;
824             $output .= $isbn->isbn . " ";
825
826             # If we successfully converted the ISBN to its counterpart, add the
827             # converted ISBN to the output as well
828             $output .= ($isbn_xlated->isbn . " ") if ($isbn_xlated);
829         }
830     }
831     return $output if $output;
832
833     # If there were no valid ISBNs, just return the raw input
834     return $input;
835 $func$ LANGUAGE PLPERLU;
836
837 COMMENT ON FUNCTION public.translate_isbn1013(TEXT) IS $$
838 /*
839  * Copyright (C) 2010 Merrimack Valley Library Consortium
840  * Jason Stephenson <jstephenson@mvlc.org>
841  * Copyright (C) 2010 Laurentian University
842  * Dan Scott <dscott@laurentian.ca>
843  *
844  * The translate_isbn1013 function takes an input ISBN and returns the
845  * following in a single space-delimited string if the input ISBN is valid:
846  *   - The normalized input ISBN (hyphens stripped)
847  *   - The normalized input ISBN with a fixed checksum if the checksum was bad
848  *   - The ISBN converted to its ISBN10 or ISBN13 counterpart, if possible
849  */
850 $$;
851
852 -- And ... a table in which to register them
853
854 CREATE TABLE config.index_normalizer (
855         id              SERIAL  PRIMARY KEY,
856         name            TEXT    UNIQUE NOT NULL,
857         description     TEXT,
858         func            TEXT    NOT NULL,
859         param_count     INT     NOT NULL DEFAULT 0
860 );
861
862 CREATE TABLE config.metabib_field_index_norm_map (
863         id      SERIAL  PRIMARY KEY,
864         field   INT     NOT NULL REFERENCES config.metabib_field (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
865         norm    INT     NOT NULL REFERENCES config.index_normalizer (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
866         params  TEXT,
867         pos     INT     NOT NULL DEFAULT 0
868 );
869
870 CREATE OR REPLACE FUNCTION oils_tsearch2 () RETURNS TRIGGER AS $$
871 DECLARE
872     normalizer      RECORD;
873     value           TEXT := '';
874 BEGIN
875
876     value := NEW.value;
877
878     IF TG_TABLE_NAME::TEXT ~ 'field_entry$' THEN
879         FOR normalizer IN
880             SELECT  n.func AS func,
881                     n.param_count AS param_count,
882                     m.params AS params
883               FROM  config.index_normalizer n
884                     JOIN config.metabib_field_index_norm_map m ON (m.norm = n.id)
885               WHERE field = NEW.field AND m.pos < 0
886               ORDER BY m.pos LOOP
887                 EXECUTE 'SELECT ' || normalizer.func || '(' ||
888                     quote_literal( value ) ||
889                     CASE
890                         WHEN normalizer.param_count > 0
891                             THEN ',' || REPLACE(REPLACE(BTRIM(normalizer.params,'[]'),E'\'',E'\\\''),E'"',E'\'')
892                             ELSE ''
893                         END ||
894                     ')' INTO value;
895
896         END LOOP;
897
898         NEW.value := value;
899     END IF;
900
901     IF NEW.index_vector = ''::tsvector THEN
902         RETURN NEW;
903     END IF;
904
905     IF TG_TABLE_NAME::TEXT ~ 'field_entry$' THEN
906         FOR normalizer IN
907             SELECT  n.func AS func,
908                     n.param_count AS param_count,
909                     m.params AS params
910               FROM  config.index_normalizer n
911                     JOIN config.metabib_field_index_norm_map m ON (m.norm = n.id)
912               WHERE field = NEW.field AND m.pos >= 0
913               ORDER BY m.pos LOOP
914                 EXECUTE 'SELECT ' || normalizer.func || '(' ||
915                     quote_literal( value ) ||
916                     CASE
917                         WHEN normalizer.param_count > 0
918                             THEN ',' || REPLACE(REPLACE(BTRIM(normalizer.params,'[]'),E'\'',E'\\\''),E'"',E'\'')
919                             ELSE ''
920                         END ||
921                     ')' INTO value;
922
923         END LOOP;
924     END IF;
925
926     IF REGEXP_REPLACE(VERSION(),E'^.+?(\\d+\\.\\d+).*?$',E'\\1')::FLOAT > 8.2 THEN
927         NEW.index_vector = to_tsvector((TG_ARGV[0])::regconfig, value);
928     ELSE
929         NEW.index_vector = to_tsvector(TG_ARGV[0], value);
930     END IF;
931
932     RETURN NEW;
933 END;
934 $$ LANGUAGE PLPGSQL;
935
936 COMMIT;