]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/sql/Pg/002.schema.config.sql
MORE: Properly support extracting MARC21 fixed fields from the leader, not just the...
[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 ('0519'); -- miker
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,
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 CREATE OR REPLACE FUNCTION config.update_hard_due_dates () RETURNS INT AS $func$
362 DECLARE
363     temp_value  config.hard_due_date_values%ROWTYPE;
364     updated     INT := 0;
365 BEGIN
366     FOR temp_value IN
367       SELECT  DISTINCT ON (hard_due_date) *
368         FROM  config.hard_due_date_values
369         WHERE active_date <= NOW() -- We've passed (or are at) the rollover time
370         ORDER BY hard_due_date, active_date DESC -- Latest (nearest to us) active time
371    LOOP
372         UPDATE  config.hard_due_date
373           SET   ceiling_date = temp_value.ceiling_date
374           WHERE id = temp_value.hard_due_date
375                 AND ceiling_date <> temp_value.ceiling_date; -- Time is equal if we've already updated the chdd
376
377         IF FOUND THEN
378             updated := updated + 1;
379         END IF;
380     END LOOP;
381
382     RETURN updated;
383 END;
384 $func$ LANGUAGE plpgsql;
385
386 CREATE TABLE config.rule_max_fine (
387     id          SERIAL          PRIMARY KEY,
388     name        TEXT            NOT NULL UNIQUE CHECK ( name ~ E'^\\w+$' ),
389     amount      NUMERIC(6,2)    NOT NULL,
390     is_percent  BOOL            NOT NULL DEFAULT FALSE
391 );
392 COMMENT ON TABLE config.rule_max_fine IS $$
393 /*
394  * Copyright (C) 2005  Georgia Public Library Service 
395  * Mike Rylander <mrylander@gmail.com>
396  *
397  * Circulation Max Fine rules
398  *
399  * Each circulation is given a maximum fine based on one of
400  * these rules.
401  * 
402  *
403  * ****
404  *
405  * This program is free software; you can redistribute it and/or
406  * modify it under the terms of the GNU General Public License
407  * as published by the Free Software Foundation; either version 2
408  * of the License, or (at your option) any later version.
409  *
410  * This program is distributed in the hope that it will be useful,
411  * but WITHOUT ANY WARRANTY; without even the implied warranty of
412  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
413  * GNU General Public License for more details.
414  */
415 $$;
416
417 CREATE TABLE config.rule_recurring_fine (
418         id                      SERIAL          PRIMARY KEY,
419         name                    TEXT            NOT NULL UNIQUE CHECK ( name ~ E'^\\w+$' ),
420         high                    NUMERIC(6,2)    NOT NULL,
421         normal                  NUMERIC(6,2)    NOT NULL,
422         low                     NUMERIC(6,2)    NOT NULL,
423         recurrence_interval     INTERVAL        NOT NULL DEFAULT '1 day'::INTERVAL,
424     grace_period       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.marc21_rec_type_map (
571     code        TEXT    PRIMARY KEY,
572     type_val    TEXT    NOT NULL,
573     blvl_val    TEXT    NOT NULL
574 );
575
576 CREATE TABLE config.marc21_ff_pos_map (
577     id          SERIAL  PRIMARY KEY,
578     fixed_field TEXT    NOT NULL,
579     tag         TEXT    NOT NULL,
580     rec_type    TEXT    NOT NULL,
581     start_pos   INT     NOT NULL,
582     length      INT     NOT NULL,
583     default_val TEXT    NOT NULL DEFAULT ' '
584 );
585
586 CREATE TABLE config.marc21_physical_characteristic_type_map (
587     ptype_key   TEXT    PRIMARY KEY,
588     label       TEXT    NOT NULL -- I18N
589 );
590
591 CREATE TABLE config.marc21_physical_characteristic_subfield_map (
592     id          SERIAL  PRIMARY KEY,
593     ptype_key   TEXT    NOT NULL REFERENCES config.marc21_physical_characteristic_type_map (ptype_key) ON DELETE CASCADE ON UPDATE CASCADE,
594     subfield    TEXT    NOT NULL,
595     start_pos   INT     NOT NULL,
596     length      INT     NOT NULL,
597     label       TEXT    NOT NULL -- I18N
598 );
599
600 CREATE TABLE config.marc21_physical_characteristic_value_map (
601     id              SERIAL  PRIMARY KEY,
602     value           TEXT    NOT NULL,
603     ptype_subfield  INT     NOT NULL REFERENCES config.marc21_physical_characteristic_subfield_map (id),
604     label           TEXT    NOT NULL -- I18N
605 );
606
607
608 CREATE TABLE config.z3950_source (
609     name                TEXT    PRIMARY KEY,
610     label               TEXT    NOT NULL UNIQUE,
611     host                TEXT    NOT NULL,
612     port                INT     NOT NULL,
613     db                  TEXT    NOT NULL,
614     record_format       TEXT    NOT NULL DEFAULT 'FI',
615     transmission_format TEXT    NOT NULL DEFAULT 'usmarc',
616     auth                BOOL    NOT NULL DEFAULT TRUE
617 );
618
619 COMMENT ON TABLE config.z3950_source IS $$
620 Z39.50 Sources
621
622 Each row in this table represents a database searchable via Z39.50.
623 $$;
624
625 COMMENT ON COLUMN config.z3950_source.record_format IS $$
626 Z39.50 element set.
627 $$;
628
629 COMMENT ON COLUMN config.z3950_source.transmission_format IS $$
630 Z39.50 preferred record syntax..
631 $$;
632
633
634 CREATE TABLE config.z3950_attr (
635     id          SERIAL  PRIMARY KEY,
636     source      TEXT    NOT NULL REFERENCES config.z3950_source (name) DEFERRABLE INITIALLY DEFERRED,
637     name        TEXT    NOT NULL,
638     label       TEXT    NOT NULL,
639     code        INT     NOT NULL,
640     format      INT     NOT NULL,
641     truncation  INT     NOT NULL DEFAULT 0,
642     CONSTRAINT z_code_format_once_per_source UNIQUE (code,format,source)
643 );
644
645 CREATE TABLE config.i18n_locale (
646     code        TEXT    PRIMARY KEY,
647     marc_code   TEXT    NOT NULL, -- should exist in config.coded_value_map WHERE ctype = 'item_lang'
648     name        TEXT    UNIQUE NOT NULL,
649     description TEXT
650 );
651
652 CREATE TABLE config.i18n_core (
653     id              BIGSERIAL   PRIMARY KEY,
654     fq_field        TEXT        NOT NULL,
655     identity_value  TEXT        NOT NULL,
656     translation     TEXT        NOT NULL    REFERENCES config.i18n_locale (code) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
657     string          TEXT        NOT NULL
658 );
659
660 CREATE UNIQUE INDEX i18n_identity ON config.i18n_core (fq_field,identity_value,translation);
661
662 CREATE OR REPLACE FUNCTION oils_i18n_update_apply(old_ident TEXT, new_ident TEXT, hint TEXT) RETURNS VOID AS $_$
663 BEGIN
664
665     EXECUTE $$
666         UPDATE  config.i18n_core
667           SET   identity_value = $$ || quote_literal(new_ident) || $$ 
668           WHERE fq_field LIKE '$$ || hint || $$.%' 
669                 AND identity_value = $$ || quote_literal(old_ident) || $$::TEXT;$$;
670
671     RETURN;
672
673 END;
674 $_$ LANGUAGE PLPGSQL;
675
676 CREATE OR REPLACE FUNCTION oils_i18n_id_tracking(/* hint */) RETURNS TRIGGER AS $_$
677 BEGIN
678     PERFORM oils_i18n_update_apply( OLD.id::TEXT, NEW.id::TEXT, TG_ARGV[0]::TEXT );
679     RETURN NEW;
680 END;
681 $_$ LANGUAGE PLPGSQL;
682
683 CREATE OR REPLACE FUNCTION oils_i18n_code_tracking(/* hint */) RETURNS TRIGGER AS $_$
684 BEGIN
685     PERFORM oils_i18n_update_apply( OLD.code::TEXT, NEW.code::TEXT, TG_ARGV[0]::TEXT );
686     RETURN NEW;
687 END;
688 $_$ LANGUAGE PLPGSQL;
689
690 CREATE TABLE config.billing_type (
691     id              SERIAL  PRIMARY KEY,
692     name            TEXT    NOT NULL,
693     owner           INT     NOT NULL, -- REFERENCES actor.org_unit (id)
694     default_price   NUMERIC(6,2),
695     CONSTRAINT billing_type_once_per_lib UNIQUE (name, owner)
696 );
697
698 CREATE TABLE config.settings_group (
699     name    TEXT PRIMARY KEY,
700     label   TEXT UNIQUE NOT NULL -- I18N
701 );
702
703 CREATE TABLE config.org_unit_setting_type (
704     name            TEXT    PRIMARY KEY,
705     label           TEXT    UNIQUE NOT NULL,
706     grp             TEXT    REFERENCES config.settings_group (name),
707     description     TEXT,
708     datatype        TEXT    NOT NULL DEFAULT 'string',
709     fm_class        TEXT,
710     view_perm       INT,
711     update_perm     INT,
712     --
713     -- define valid datatypes
714     --
715     CONSTRAINT coust_valid_datatype CHECK ( datatype IN
716     ( 'bool', 'integer', 'float', 'currency', 'interval',
717       'date', 'string', 'object', 'array', 'link' ) ),
718     --
719     -- fm_class is meaningful only for 'link' datatype
720     --
721     CONSTRAINT coust_no_empty_link CHECK
722     ( ( datatype =  'link' AND fm_class IS NOT NULL ) OR
723       ( datatype <> 'link' AND fm_class IS NULL ) )
724 );
725
726 CREATE TABLE config.usr_setting_type (
727
728     name TEXT PRIMARY KEY,
729     opac_visible BOOL NOT NULL DEFAULT FALSE,
730     label TEXT UNIQUE NOT NULL,
731     description TEXT,
732     grp             TEXT    REFERENCES config.settings_group (name),
733     datatype TEXT NOT NULL DEFAULT 'string',
734     fm_class TEXT,
735
736     --
737     -- define valid datatypes
738     --
739     CONSTRAINT coust_valid_datatype CHECK ( datatype IN
740     ( 'bool', 'integer', 'float', 'currency', 'interval',
741         'date', 'string', 'object', 'array', 'link' ) ),
742
743     --
744     -- fm_class is meaningful only for 'link' datatype
745     --
746     CONSTRAINT coust_no_empty_link CHECK
747     ( ( datatype = 'link' AND fm_class IS NOT NULL ) OR
748         ( datatype <> 'link' AND fm_class IS NULL ) )
749
750 );
751
752 -- Some handy functions, based on existing ones, to provide optional ingest normalization
753
754 CREATE OR REPLACE FUNCTION public.left_trunc( TEXT, INT ) RETURNS TEXT AS $func$
755         SELECT SUBSTRING($1,$2);
756 $func$ LANGUAGE SQL STRICT IMMUTABLE;
757
758 CREATE OR REPLACE FUNCTION public.right_trunc( TEXT, INT ) RETURNS TEXT AS $func$
759         SELECT SUBSTRING($1,1,$2);
760 $func$ LANGUAGE SQL STRICT IMMUTABLE;
761
762 CREATE OR REPLACE FUNCTION public.split_date_range( TEXT ) RETURNS TEXT AS $func$
763         SELECT REGEXP_REPLACE( $1, E'(\\d{4})-(\\d{4})', E'\\1 \\2', 'g' );
764 $func$ LANGUAGE SQL STRICT IMMUTABLE;
765
766 CREATE OR REPLACE FUNCTION public.approximate_date( TEXT, TEXT ) RETURNS TEXT AS $func$
767         SELECT REGEXP_REPLACE( $1, E'\\D', $2, 'g' );
768 $func$ LANGUAGE SQL STRICT IMMUTABLE;
769
770 CREATE OR REPLACE FUNCTION public.approximate_low_date( TEXT ) RETURNS TEXT AS $func$
771         SELECT approximate_date( $1, '0');
772 $func$ LANGUAGE SQL STRICT IMMUTABLE;
773
774 CREATE OR REPLACE FUNCTION public.approximate_high_date( TEXT ) RETURNS TEXT AS $func$
775         SELECT approximate_date( $1, '9');
776 $func$ LANGUAGE SQL STRICT IMMUTABLE;
777
778 CREATE OR REPLACE FUNCTION public.content_or_null( TEXT ) RETURNS TEXT AS $func$
779         SELECT CASE WHEN $1 ~ E'^\\s*$' THEN NULL ELSE $1 END
780 $func$ LANGUAGE SQL STRICT IMMUTABLE;
781
782 CREATE OR REPLACE FUNCTION public.integer_or_null( TEXT ) RETURNS TEXT AS $func$
783         SELECT CASE WHEN $1 ~ E'^\\d+$' THEN $1 ELSE NULL END
784 $func$ LANGUAGE SQL STRICT IMMUTABLE;
785
786 CREATE OR REPLACE FUNCTION public.force_to_isbn13( TEXT ) RETURNS TEXT AS $func$
787     use Business::ISBN;
788     use strict;
789     use warnings;
790
791     # Find the first ISBN, force it to ISBN13 and return it
792
793     my $input = shift;
794
795     foreach my $word (split(/\s/, $input)) {
796         my $isbn = Business::ISBN->new($word);
797
798         # First check the checksum; if it is not valid, fix it and add the original
799         # bad-checksum ISBN to the output
800         if ($isbn && $isbn->is_valid_checksum() == Business::ISBN::BAD_CHECKSUM) {
801             $isbn->fix_checksum();
802         }
803
804         # If we now have a valid ISBN, force it to ISBN13 and return it
805         return $isbn->as_isbn13->isbn if ($isbn && $isbn->is_valid());
806     }
807     return undef;
808 $func$ LANGUAGE PLPERLU;
809
810 COMMENT ON FUNCTION public.force_to_isbn13(TEXT) IS $$
811 /*
812  * Copyright (C) 2011 Equinox Software
813  * Mike Rylander <mrylander@gmail.com>
814  *
815  * Inspired by translate_isbn1013
816  *
817  * The force_to_isbn13 function takes an input ISBN and returns the ISBN13
818  * version without hypens and with a repaired checksum if the checksum was bad
819  */
820 $$;
821
822
823 CREATE OR REPLACE FUNCTION public.translate_isbn1013( TEXT ) RETURNS TEXT AS $func$
824     use Business::ISBN;
825     use strict;
826     use warnings;
827
828     # For each ISBN found in a single string containing a set of ISBNs:
829     #   * Normalize an incoming ISBN to have the correct checksum and no hyphens
830     #   * Convert an incoming ISBN10 or ISBN13 to its counterpart and return
831
832     my $input = shift;
833     my $output = '';
834
835     foreach my $word (split(/\s/, $input)) {
836         my $isbn = Business::ISBN->new($word);
837
838         # First check the checksum; if it is not valid, fix it and add the original
839         # bad-checksum ISBN to the output
840         if ($isbn && $isbn->is_valid_checksum() == Business::ISBN::BAD_CHECKSUM) {
841             $output .= $isbn->isbn() . " ";
842             $isbn->fix_checksum();
843         }
844
845         # If we now have a valid ISBN, convert it to its counterpart ISBN10/ISBN13
846         # and add the normalized original ISBN to the output
847         if ($isbn && $isbn->is_valid()) {
848             my $isbn_xlated = ($isbn->type eq "ISBN13") ? $isbn->as_isbn10 : $isbn->as_isbn13;
849             $output .= $isbn->isbn . " ";
850
851             # If we successfully converted the ISBN to its counterpart, add the
852             # converted ISBN to the output as well
853             $output .= ($isbn_xlated->isbn . " ") if ($isbn_xlated);
854         }
855     }
856     return $output if $output;
857
858     # If there were no valid ISBNs, just return the raw input
859     return $input;
860 $func$ LANGUAGE PLPERLU;
861
862 COMMENT ON FUNCTION public.translate_isbn1013(TEXT) IS $$
863 /*
864  * Copyright (C) 2010 Merrimack Valley Library Consortium
865  * Jason Stephenson <jstephenson@mvlc.org>
866  * Copyright (C) 2010 Laurentian University
867  * Dan Scott <dscott@laurentian.ca>
868  *
869  * The translate_isbn1013 function takes an input ISBN and returns the
870  * following in a single space-delimited string if the input ISBN is valid:
871  *   - The normalized input ISBN (hyphens stripped)
872  *   - The normalized input ISBN with a fixed checksum if the checksum was bad
873  *   - The ISBN converted to its ISBN10 or ISBN13 counterpart, if possible
874  */
875 $$;
876
877 -- And ... a table in which to register them
878
879 CREATE TABLE config.index_normalizer (
880         id              SERIAL  PRIMARY KEY,
881         name            TEXT    UNIQUE NOT NULL,
882         description     TEXT,
883         func            TEXT    NOT NULL,
884         param_count     INT     NOT NULL DEFAULT 0
885 );
886
887 CREATE TABLE config.metabib_field_index_norm_map (
888         id      SERIAL  PRIMARY KEY,
889         field   INT     NOT NULL REFERENCES config.metabib_field (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
890         norm    INT     NOT NULL REFERENCES config.index_normalizer (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
891         params  TEXT,
892         pos     INT     NOT NULL DEFAULT 0
893 );
894
895 CREATE TABLE config.record_attr_definition (
896     name        TEXT    PRIMARY KEY,
897     label       TEXT    NOT NULL, -- I18N
898     description TEXT,
899     filter      BOOL    NOT NULL DEFAULT TRUE,  -- becomes QP filter if true
900     sorter      BOOL    NOT NULL DEFAULT FALSE, -- becomes QP sort() axis if true
901
902 -- For pre-extracted fields. Takes the first occurance, uses naive subfield ordering
903     tag         TEXT, -- LIKE format
904     sf_list     TEXT, -- pile-o-values, like 'abcd' for a and b and c and d
905
906 -- This is used for both tag/sf and xpath entries
907     joiner      TEXT,
908
909 -- For xpath-extracted attrs
910     xpath       TEXT,
911     format      TEXT    REFERENCES config.xml_transform (name) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
912     start_pos   INT,
913     string_len  INT,
914
915 -- For fixed fields
916     fixed_field TEXT, -- should exist in config.marc21_ff_pos_map.fixed_field
917
918 -- For phys-char fields
919     phys_char_sf    INT REFERENCES config.marc21_physical_characteristic_subfield_map (id)
920 );
921
922 CREATE TABLE config.record_attr_index_norm_map (
923     id      SERIAL  PRIMARY KEY,
924     attr    TEXT    NOT NULL REFERENCES config.record_attr_definition (name) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
925     norm    INT     NOT NULL REFERENCES config.index_normalizer (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
926     params  TEXT,
927     pos     INT     NOT NULL DEFAULT 0
928 );
929
930 CREATE TABLE config.coded_value_map (
931     id          SERIAL  PRIMARY KEY,
932     ctype       TEXT    NOT NULL REFERENCES config.record_attr_definition (name) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
933     code        TEXT    NOT NULL,
934     value       TEXT    NOT NULL,
935     description TEXT
936 );
937
938 CREATE VIEW config.language_map AS SELECT code, value FROM config.coded_value_map WHERE ctype = 'item_lang';
939 CREATE VIEW config.bib_level_map AS SELECT code, value FROM config.coded_value_map WHERE ctype = 'bib_level';
940 CREATE VIEW config.item_form_map AS SELECT code, value FROM config.coded_value_map WHERE ctype = 'item_form';
941 CREATE VIEW config.item_type_map AS SELECT code, value FROM config.coded_value_map WHERE ctype = 'item_type';
942 CREATE VIEW config.lit_form_map AS SELECT code, value, description FROM config.coded_value_map WHERE ctype = 'lit_form';
943 CREATE VIEW config.audience_map AS SELECT code, value, description FROM config.coded_value_map WHERE ctype = 'audience';
944 CREATE VIEW config.videorecording_format_map AS SELECT code, value FROM config.coded_value_map WHERE ctype = 'vr_format';
945
946 CREATE OR REPLACE FUNCTION oils_tsearch2 () RETURNS TRIGGER AS $$
947 DECLARE
948     normalizer      RECORD;
949     value           TEXT := '';
950 BEGIN
951
952     value := NEW.value;
953
954     IF TG_TABLE_NAME::TEXT ~ 'field_entry$' THEN
955         FOR normalizer IN
956             SELECT  n.func AS func,
957                     n.param_count AS param_count,
958                     m.params AS params
959               FROM  config.index_normalizer n
960                     JOIN config.metabib_field_index_norm_map m ON (m.norm = n.id)
961               WHERE field = NEW.field AND m.pos < 0
962               ORDER BY m.pos LOOP
963                 EXECUTE 'SELECT ' || normalizer.func || '(' ||
964                     quote_literal( value ) ||
965                     CASE
966                         WHEN normalizer.param_count > 0
967                             THEN ',' || REPLACE(REPLACE(BTRIM(normalizer.params,'[]'),E'\'',E'\\\''),E'"',E'\'')
968                             ELSE ''
969                         END ||
970                     ')' INTO value;
971
972         END LOOP;
973
974         NEW.value := value;
975     END IF;
976
977     IF NEW.index_vector = ''::tsvector THEN
978         RETURN NEW;
979     END IF;
980
981     IF TG_TABLE_NAME::TEXT ~ 'field_entry$' THEN
982         FOR normalizer IN
983             SELECT  n.func AS func,
984                     n.param_count AS param_count,
985                     m.params AS params
986               FROM  config.index_normalizer n
987                     JOIN config.metabib_field_index_norm_map m ON (m.norm = n.id)
988               WHERE field = NEW.field AND m.pos >= 0
989               ORDER BY m.pos LOOP
990                 EXECUTE 'SELECT ' || normalizer.func || '(' ||
991                     quote_literal( value ) ||
992                     CASE
993                         WHEN normalizer.param_count > 0
994                             THEN ',' || REPLACE(REPLACE(BTRIM(normalizer.params,'[]'),E'\'',E'\\\''),E'"',E'\'')
995                             ELSE ''
996                         END ||
997                     ')' INTO value;
998
999         END LOOP;
1000     END IF;
1001
1002     IF REGEXP_REPLACE(VERSION(),E'^.+?(\\d+\\.\\d+).*?$',E'\\1')::FLOAT > 8.2 THEN
1003         NEW.index_vector = to_tsvector((TG_ARGV[0])::regconfig, value);
1004     ELSE
1005         NEW.index_vector = to_tsvector(TG_ARGV[0], value);
1006     END IF;
1007
1008     RETURN NEW;
1009 END;
1010 $$ LANGUAGE PLPGSQL;
1011
1012 COMMIT;