]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/sql/Pg/version-upgrade/2.9.3-2.10.0-upgrade-db.sql
LP#1772028 Add some FK violation functions just in case they are missing
[Evergreen.git] / Open-ILS / src / sql / Pg / version-upgrade / 2.9.3-2.10.0-upgrade-db.sql
1 --Upgrade Script for 2.9.3 to 2.10.0
2 \set eg_version '''2.10.0'''
3 BEGIN;
4
5 INSERT INTO config.upgrade_log (version, applied_to) VALUES ('2.10.0', :eg_version);
6
7 SELECT evergreen.upgrade_deps_block_check('0945', :eg_version);
8
9 -- run the entire update inside a DO block for managing the logic
10 -- of whether to recreate the optional reporter views
11 DO $$
12 DECLARE
13     has_current_circ BOOLEAN;
14     has_billing_summary BOOLEAN;
15 BEGIN
16
17 SELECT INTO has_current_circ TRUE FROM pg_views 
18     WHERE schemaname = 'reporter' AND viewname = 'classic_current_circ';
19
20 SELECT INTO has_billing_summary TRUE FROM pg_views 
21     WHERE schemaname = 'reporter' AND 
22     viewname = 'classic_current_billing_summary';
23
24 DROP VIEW action.all_circulation;
25 DROP VIEW IF EXISTS reporter.classic_current_circ;
26 DROP VIEW IF EXISTS reporter.classic_current_billing_summary;
27 DROP VIEW reporter.demographic;
28 DROP VIEW auditor.actor_usr_lifecycle;
29 DROP VIEW action.all_hold_request;
30
31 ALTER TABLE actor.usr 
32     ALTER dob TYPE DATE USING (dob + '3 hours'::INTERVAL)::DATE;
33
34 -- alter the auditor table manually to apply the same
35 -- dob mangling logic as above.
36 ALTER TABLE auditor.actor_usr_history 
37     ALTER dob TYPE DATE USING (dob + '3 hours'::INTERVAL)::DATE;
38
39 -- this recreates auditor.actor_usr_lifecycle
40 PERFORM auditor.update_auditors();
41
42 CREATE VIEW reporter.demographic AS
43     SELECT u.id, u.dob,
44         CASE
45             WHEN u.dob IS NULL THEN 'Adult'::text
46             WHEN age(u.dob) > '18 years'::interval THEN 'Adult'::text
47             ELSE 'Juvenile'::text
48         END AS general_division
49     FROM actor.usr u;
50
51 CREATE VIEW action.all_circulation AS
52          SELECT aged_circulation.id, aged_circulation.usr_post_code,
53             aged_circulation.usr_home_ou, aged_circulation.usr_profile,
54             aged_circulation.usr_birth_year, aged_circulation.copy_call_number,
55             aged_circulation.copy_location, aged_circulation.copy_owning_lib,
56             aged_circulation.copy_circ_lib, aged_circulation.copy_bib_record,
57             aged_circulation.xact_start, aged_circulation.xact_finish,
58             aged_circulation.target_copy, aged_circulation.circ_lib,
59             aged_circulation.circ_staff, aged_circulation.checkin_staff,
60             aged_circulation.checkin_lib, aged_circulation.renewal_remaining,
61             aged_circulation.grace_period, aged_circulation.due_date,
62             aged_circulation.stop_fines_time, aged_circulation.checkin_time,
63             aged_circulation.create_time, aged_circulation.duration,
64             aged_circulation.fine_interval, aged_circulation.recurring_fine,
65             aged_circulation.max_fine, aged_circulation.phone_renewal,
66             aged_circulation.desk_renewal, aged_circulation.opac_renewal,
67             aged_circulation.duration_rule,
68             aged_circulation.recurring_fine_rule,
69             aged_circulation.max_fine_rule, aged_circulation.stop_fines,
70             aged_circulation.workstation, aged_circulation.checkin_workstation,
71             aged_circulation.checkin_scan_time, aged_circulation.parent_circ
72            FROM action.aged_circulation
73 UNION ALL
74          SELECT DISTINCT circ.id,
75             COALESCE(a.post_code, b.post_code) AS usr_post_code,
76             p.home_ou AS usr_home_ou, p.profile AS usr_profile,
77             date_part('year'::text, p.dob)::integer AS usr_birth_year,
78             cp.call_number AS copy_call_number, circ.copy_location,
79             cn.owning_lib AS copy_owning_lib, cp.circ_lib AS copy_circ_lib,
80             cn.record AS copy_bib_record, circ.xact_start, circ.xact_finish,
81             circ.target_copy, circ.circ_lib, circ.circ_staff,
82             circ.checkin_staff, circ.checkin_lib, circ.renewal_remaining,
83             circ.grace_period, circ.due_date, circ.stop_fines_time,
84             circ.checkin_time, circ.create_time, circ.duration,
85             circ.fine_interval, circ.recurring_fine, circ.max_fine,
86             circ.phone_renewal, circ.desk_renewal, circ.opac_renewal,
87             circ.duration_rule, circ.recurring_fine_rule, circ.max_fine_rule,
88             circ.stop_fines, circ.workstation, circ.checkin_workstation,
89             circ.checkin_scan_time, circ.parent_circ
90            FROM action.circulation circ
91       JOIN asset.copy cp ON circ.target_copy = cp.id
92    JOIN asset.call_number cn ON cp.call_number = cn.id
93    JOIN actor.usr p ON circ.usr = p.id
94    LEFT JOIN actor.usr_address a ON p.mailing_address = a.id
95    LEFT JOIN actor.usr_address b ON p.billing_address = b.id;
96
97 CREATE OR REPLACE VIEW action.all_hold_request AS
98          SELECT DISTINCT COALESCE(a.post_code, b.post_code) AS usr_post_code,
99             p.home_ou AS usr_home_ou, p.profile AS usr_profile,
100             date_part('year'::text, p.dob)::integer AS usr_birth_year,
101             ahr.requestor <> ahr.usr AS staff_placed, ahr.id, ahr.request_time,
102             ahr.capture_time, ahr.fulfillment_time, ahr.checkin_time,
103             ahr.return_time, ahr.prev_check_time, ahr.expire_time,
104             ahr.cancel_time, ahr.cancel_cause, ahr.cancel_note, ahr.target,
105             ahr.current_copy, ahr.fulfillment_staff, ahr.fulfillment_lib,
106             ahr.request_lib, ahr.selection_ou, ahr.selection_depth,
107             ahr.pickup_lib, ahr.hold_type, ahr.holdable_formats,
108                 CASE
109                     WHEN ahr.phone_notify IS NULL THEN false
110                     WHEN ahr.phone_notify = ''::text THEN false
111                     ELSE true
112                 END AS phone_notify,
113             ahr.email_notify,
114                 CASE
115                     WHEN ahr.sms_notify IS NULL THEN false
116                     WHEN ahr.sms_notify = ''::text THEN false
117                     ELSE true
118                 END AS sms_notify,
119             ahr.frozen, ahr.thaw_date, ahr.shelf_time, ahr.cut_in_line,
120             ahr.mint_condition, ahr.shelf_expire_time, ahr.current_shelf_lib,
121             ahr.behind_desk
122            FROM action.hold_request ahr
123       JOIN actor.usr p ON ahr.usr = p.id
124    LEFT JOIN actor.usr_address a ON p.mailing_address = a.id
125    LEFT JOIN actor.usr_address b ON p.billing_address = b.id
126 UNION ALL
127          SELECT aged_hold_request.usr_post_code, aged_hold_request.usr_home_ou,
128             aged_hold_request.usr_profile, aged_hold_request.usr_birth_year,
129             aged_hold_request.staff_placed, aged_hold_request.id,
130             aged_hold_request.request_time, aged_hold_request.capture_time,
131             aged_hold_request.fulfillment_time, aged_hold_request.checkin_time,
132             aged_hold_request.return_time, aged_hold_request.prev_check_time,
133             aged_hold_request.expire_time, aged_hold_request.cancel_time,
134             aged_hold_request.cancel_cause, aged_hold_request.cancel_note,
135             aged_hold_request.target, aged_hold_request.current_copy,
136             aged_hold_request.fulfillment_staff,
137             aged_hold_request.fulfillment_lib, aged_hold_request.request_lib,
138             aged_hold_request.selection_ou, aged_hold_request.selection_depth,
139             aged_hold_request.pickup_lib, aged_hold_request.hold_type,
140             aged_hold_request.holdable_formats, aged_hold_request.phone_notify,
141             aged_hold_request.email_notify, aged_hold_request.sms_notify,
142             aged_hold_request.frozen, aged_hold_request.thaw_date,
143             aged_hold_request.shelf_time, aged_hold_request.cut_in_line,
144             aged_hold_request.mint_condition,
145             aged_hold_request.shelf_expire_time,
146             aged_hold_request.current_shelf_lib, aged_hold_request.behind_desk
147            FROM action.aged_hold_request;
148
149 IF has_current_circ THEN
150 RAISE NOTICE 'Recreating optional view reporter.classic_current_circ';
151
152 CREATE OR REPLACE VIEW reporter.classic_current_circ AS
153 SELECT  cl.shortname AS circ_lib,
154         cl.id AS circ_lib_id,
155         circ.xact_start AS xact_start,
156         circ_type.type AS circ_type,
157         cp.id AS copy_id,
158         cp.circ_modifier,
159         ol.shortname AS owning_lib_name,
160         lm.value AS language,
161         lfm.value AS lit_form,
162         ifm.value AS item_form,
163         itm.value AS item_type,
164         sl.name AS shelving_location,
165         p.id AS patron_id,
166         g.name AS profile_group,
167         dem.general_division AS demographic_general_division,
168         circ.id AS id,
169         cn.id AS call_number,
170         cn.label AS call_number_label,
171         call_number_dewey(cn.label) AS dewey,
172         CASE
173                 WHEN call_number_dewey(cn.label) ~  E'^[0-9.]+$'
174                         THEN
175                                 btrim(
176                                         to_char(
177                                                 10 * floor((call_number_dewey(cn.label)::float) / 10), '000'
178                                         )
179                                 )
180                 ELSE NULL
181         END AS dewey_block_tens,
182         CASE
183                 WHEN call_number_dewey(cn.label) ~  E'^[0-9.]+$'
184                         THEN
185                                 btrim(
186                                         to_char(
187                                                 100 * floor((call_number_dewey(cn.label)::float) / 100), '000'
188                                         )
189                                 )
190                 ELSE NULL
191         END AS dewey_block_hundreds,
192         CASE
193                 WHEN call_number_dewey(cn.label) ~  E'^[0-9.]+$'
194                         THEN
195                                 btrim(
196                                         to_char(
197                                                 10 * floor((call_number_dewey(cn.label)::float) / 10), '000'
198                                         )
199                                 )
200                                 || '-' ||
201                                 btrim(
202                                         to_char(
203                                                 10 * floor((call_number_dewey(cn.label)::float) / 10) + 9, '000'
204                                         )
205                                 )
206                 ELSE NULL
207         END AS dewey_range_tens,
208         CASE
209                 WHEN call_number_dewey(cn.label) ~  E'^[0-9.]+$'
210                         THEN
211                                 btrim(
212                                         to_char(
213                                                 100 * floor((call_number_dewey(cn.label)::float) / 100), '000'
214                                         )
215                                 )
216                                 || '-' ||
217                                 btrim(
218                                         to_char(
219                                                 100 * floor((call_number_dewey(cn.label)::float) / 100) + 99, '000'
220                                         )
221                                 )
222                 ELSE NULL
223         END AS dewey_range_hundreds,
224         hl.id AS patron_home_lib,
225         hl.shortname AS patron_home_lib_shortname,
226         paddr.county AS patron_county,
227         paddr.city AS patron_city,
228         paddr.post_code AS patron_zip,
229         sc1.stat_cat_entry AS stat_cat_1,
230         sc2.stat_cat_entry AS stat_cat_2,
231         sce1.value AS stat_cat_1_value,
232         sce2.value AS stat_cat_2_value
233   FROM  action.circulation circ
234         JOIN reporter.circ_type circ_type ON (circ.id = circ_type.id)
235         JOIN asset.copy cp ON (cp.id = circ.target_copy)
236         JOIN asset.copy_location sl ON (cp.location = sl.id)
237         JOIN asset.call_number cn ON (cp.call_number = cn.id)
238         JOIN actor.org_unit ol ON (cn.owning_lib = ol.id)
239         JOIN metabib.rec_descriptor rd ON (rd.record = cn.record)
240         JOIN actor.org_unit cl ON (circ.circ_lib = cl.id)
241         JOIN actor.usr p ON (p.id = circ.usr)
242         JOIN actor.org_unit hl ON (p.home_ou = hl.id)
243         JOIN permission.grp_tree g ON (p.profile = g.id)
244         JOIN reporter.demographic dem ON (dem.id = p.id)
245         JOIN actor.usr_address paddr ON (paddr.id = p.billing_address)
246         LEFT JOIN config.language_map lm ON (rd.item_lang = lm.code)
247         LEFT JOIN config.lit_form_map lfm ON (rd.lit_form = lfm.code)
248         LEFT JOIN config.item_form_map ifm ON (rd.item_form = ifm.code)
249         LEFT JOIN config.item_type_map itm ON (rd.item_type = itm.code)
250         LEFT JOIN asset.stat_cat_entry_copy_map sc1 ON (sc1.owning_copy = cp.id AND sc1.stat_cat = 1)
251         LEFT JOIN asset.stat_cat_entry sce1 ON (sce1.id = sc1.stat_cat_entry)
252         LEFT JOIN asset.stat_cat_entry_copy_map sc2 ON (sc2.owning_copy = cp.id AND sc2.stat_cat = 2)
253         LEFT JOIN asset.stat_cat_entry sce2 ON (sce2.id = sc2.stat_cat_entry);
254 END IF;
255
256 IF has_billing_summary THEN
257 RAISE NOTICE 'Recreating optional view reporter.classic_current_billing_summary';
258
259 CREATE OR REPLACE VIEW reporter.classic_current_billing_summary AS
260 SELECT  x.id AS id,
261         x.usr AS usr,
262         bl.shortname AS billing_location_shortname,
263         bl.name AS billing_location_name,
264         x.billing_location AS billing_location,
265         c.barcode AS barcode,
266         u.home_ou AS usr_home_ou,
267         ul.shortname AS usr_home_ou_shortname,
268         ul.name AS usr_home_ou_name,
269         x.xact_start AS xact_start,
270         x.xact_finish AS xact_finish,
271         x.xact_type AS xact_type,
272         x.total_paid AS total_paid,
273         x.total_owed AS total_owed,
274         x.balance_owed AS balance_owed,
275         x.last_payment_ts AS last_payment_ts,
276         x.last_payment_note AS last_payment_note,
277         x.last_payment_type AS last_payment_type,
278         x.last_billing_ts AS last_billing_ts,
279         x.last_billing_note AS last_billing_note,
280         x.last_billing_type AS last_billing_type,
281         paddr.county AS patron_county,
282         paddr.city AS patron_city,
283         paddr.post_code AS patron_zip,
284         g.name AS profile_group,
285         dem.general_division AS demographic_general_division
286   FROM  money.open_billable_xact_summary x
287         JOIN actor.org_unit bl ON (x.billing_location = bl.id)
288         JOIN actor.usr u ON (u.id = x.usr)
289         JOIN actor.org_unit ul ON (u.home_ou = ul.id)
290         JOIN actor.card c ON (u.card = c.id)
291         JOIN permission.grp_tree g ON (u.profile = g.id)
292         JOIN reporter.demographic dem ON (dem.id = u.id)
293         JOIN actor.usr_address paddr ON (paddr.id = u.billing_address);
294 END IF;
295
296 END $$;
297
298 SELECT evergreen.upgrade_deps_block_check('0946', :eg_version);
299
300 CREATE OR REPLACE FUNCTION actor.org_unit_ancestor_setting_batch( org_id INT, VARIADIC setting_names TEXT[] ) RETURNS SETOF actor.org_unit_setting AS $$
301 DECLARE
302     setting RECORD;
303     setting_name TEXT;
304     cur_org INT;
305 BEGIN
306     FOREACH setting_name IN ARRAY setting_names
307     LOOP
308         cur_org := org_id;
309         LOOP
310             SELECT INTO setting * FROM actor.org_unit_setting WHERE org_unit = cur_org AND name = setting_name;
311             IF FOUND THEN
312                 RETURN NEXT setting;
313                 EXIT;
314             END IF;
315             SELECT INTO cur_org parent_ou FROM actor.org_unit WHERE id = cur_org;
316             EXIT WHEN cur_org IS NULL;
317         END LOOP;
318     END LOOP;
319     RETURN;
320 END;
321 $$ LANGUAGE plpgsql STABLE;
322
323 COMMENT ON FUNCTION actor.org_unit_ancestor_setting_batch( INT, VARIADIC TEXT[] ) IS $$
324 For each setting name passed, search "up" the org_unit tree until
325 we find the first occurrence of an org_unit_setting with the given name.
326 $$;
327
328 SELECT evergreen.upgrade_deps_block_check('0947', :eg_version);
329
330 CREATE OR REPLACE FUNCTION evergreen.lpad_number_substrings( TEXT, TEXT, INT ) RETURNS TEXT AS $$
331     my $string = shift;            # Source string
332     my $pad = shift;               # string to fill. Typically '0'. This should be a single character.
333     my $len = shift;               # length of resultant padded field
334
335     $string =~ s/([0-9]+)/$pad x ($len - length($1)) . $1/eg;
336
337     return $string;
338 $$ LANGUAGE PLPERLU;
339
340 SELECT evergreen.upgrade_deps_block_check('0951', :eg_version);
341
342 ALTER TABLE config.standing_penalty
343       ADD COLUMN ignore_proximity INTEGER;
344
345 CREATE OR REPLACE FUNCTION action.hold_request_permit_test( pickup_ou INT, request_ou INT, match_item BIGINT, match_user INT, match_requestor INT, retargetting BOOL ) RETURNS SETOF action.matrix_test_result AS $func$
346 DECLARE
347     matchpoint_id        INT;
348     user_object        actor.usr%ROWTYPE;
349     age_protect_object    config.rule_age_hold_protect%ROWTYPE;
350     standing_penalty    config.standing_penalty%ROWTYPE;
351     transit_range_ou_type    actor.org_unit_type%ROWTYPE;
352     transit_source        actor.org_unit%ROWTYPE;
353     item_object        asset.copy%ROWTYPE;
354     item_cn_object     asset.call_number%ROWTYPE;
355     item_status_object  config.copy_status%ROWTYPE;
356     item_location_object    asset.copy_location%ROWTYPE;
357     ou_skip              actor.org_unit_setting%ROWTYPE;
358     result            action.matrix_test_result;
359     hold_test        config.hold_matrix_matchpoint%ROWTYPE;
360     use_active_date   TEXT;
361     age_protect_date  TIMESTAMP WITH TIME ZONE;
362     hold_count        INT;
363     hold_transit_prox    INT;
364     frozen_hold_count    INT;
365     context_org_list    INT[];
366     done            BOOL := FALSE;
367     hold_penalty TEXT;
368     v_pickup_ou ALIAS FOR pickup_ou;
369     v_request_ou ALIAS FOR request_ou;
370     item_prox INT;
371     pickup_prox INT;
372 BEGIN
373     SELECT INTO user_object * FROM actor.usr WHERE id = match_user;
374     SELECT INTO context_org_list ARRAY_AGG(id) FROM actor.org_unit_full_path( v_pickup_ou );
375
376     result.success := TRUE;
377
378     -- The HOLD penalty block only applies to new holds.
379     -- The CAPTURE penalty block applies to existing holds.
380     hold_penalty := 'HOLD';
381     IF retargetting THEN
382         hold_penalty := 'CAPTURE';
383     END IF;
384
385     -- Fail if we couldn't find a user
386     IF user_object.id IS NULL THEN
387         result.fail_part := 'no_user';
388         result.success := FALSE;
389         done := TRUE;
390         RETURN NEXT result;
391         RETURN;
392     END IF;
393
394     SELECT INTO item_object * FROM asset.copy WHERE id = match_item;
395
396     -- Fail if we couldn't find a copy
397     IF item_object.id IS NULL THEN
398         result.fail_part := 'no_item';
399         result.success := FALSE;
400         done := TRUE;
401         RETURN NEXT result;
402         RETURN;
403     END IF;
404
405     SELECT INTO matchpoint_id action.find_hold_matrix_matchpoint(v_pickup_ou, v_request_ou, match_item, match_user, match_requestor);
406     result.matchpoint := matchpoint_id;
407
408     SELECT INTO ou_skip * FROM actor.org_unit_setting WHERE name = 'circ.holds.target_skip_me' AND org_unit = item_object.circ_lib;
409
410     -- Fail if the circ_lib for the item has circ.holds.target_skip_me set to true
411     IF ou_skip.id IS NOT NULL AND ou_skip.value = 'true' THEN
412         result.fail_part := 'circ.holds.target_skip_me';
413         result.success := FALSE;
414         done := TRUE;
415         RETURN NEXT result;
416         RETURN;
417     END IF;
418
419     -- Fail if user is barred
420     IF user_object.barred IS TRUE THEN
421         result.fail_part := 'actor.usr.barred';
422         result.success := FALSE;
423         done := TRUE;
424         RETURN NEXT result;
425         RETURN;
426     END IF;
427
428     SELECT INTO item_cn_object * FROM asset.call_number WHERE id = item_object.call_number;
429     SELECT INTO item_status_object * FROM config.copy_status WHERE id = item_object.status;
430     SELECT INTO item_location_object * FROM asset.copy_location WHERE id = item_object.location;
431
432     -- Fail if we couldn't find any matchpoint (requires a default)
433     IF matchpoint_id IS NULL THEN
434         result.fail_part := 'no_matchpoint';
435         result.success := FALSE;
436         done := TRUE;
437         RETURN NEXT result;
438         RETURN;
439     END IF;
440
441     SELECT INTO hold_test * FROM config.hold_matrix_matchpoint WHERE id = matchpoint_id;
442
443     IF hold_test.holdable IS FALSE THEN
444         result.fail_part := 'config.hold_matrix_test.holdable';
445         result.success := FALSE;
446         done := TRUE;
447         RETURN NEXT result;
448     END IF;
449
450     IF item_object.holdable IS FALSE THEN
451         result.fail_part := 'item.holdable';
452         result.success := FALSE;
453         done := TRUE;
454         RETURN NEXT result;
455     END IF;
456
457     IF item_status_object.holdable IS FALSE THEN
458         result.fail_part := 'status.holdable';
459         result.success := FALSE;
460         done := TRUE;
461         RETURN NEXT result;
462     END IF;
463
464     IF item_location_object.holdable IS FALSE THEN
465         result.fail_part := 'location.holdable';
466         result.success := FALSE;
467         done := TRUE;
468         RETURN NEXT result;
469     END IF;
470
471     IF hold_test.transit_range IS NOT NULL THEN
472         SELECT INTO transit_range_ou_type * FROM actor.org_unit_type WHERE id = hold_test.transit_range;
473         IF hold_test.distance_is_from_owner THEN
474             SELECT INTO transit_source ou.* FROM actor.org_unit ou JOIN asset.call_number cn ON (cn.owning_lib = ou.id) WHERE cn.id = item_object.call_number;
475         ELSE
476             SELECT INTO transit_source * FROM actor.org_unit WHERE id = item_object.circ_lib;
477         END IF;
478
479         PERFORM * FROM actor.org_unit_descendants( transit_source.id, transit_range_ou_type.depth ) WHERE id = v_pickup_ou;
480
481         IF NOT FOUND THEN
482             result.fail_part := 'transit_range';
483             result.success := FALSE;
484             done := TRUE;
485             RETURN NEXT result;
486         END IF;
487     END IF;
488  
489     -- Proximity of user's home_ou to the pickup_lib to see if penalty should be ignored.
490     SELECT INTO pickup_prox prox FROM actor.org_unit_proximity WHERE from_org = user_object.home_ou AND to_org = v_pickup_ou;
491     -- Proximity of user's home_ou to the items' lib to see if penalty should be ignored.
492     IF hold_test.distance_is_from_owner THEN
493         SELECT INTO item_prox prox FROM actor.org_unit_proximity WHERE from_org = user_object.home_ou AND to_org = item_cn_object.owning_lib;
494     ELSE
495         SELECT INTO item_prox prox FROM actor.org_unit_proximity WHERE from_org = user_object.home_ou AND to_org = item_object.circ_lib;
496     END IF;
497
498     FOR standing_penalty IN
499         SELECT  DISTINCT csp.*
500           FROM  actor.usr_standing_penalty usp
501                 JOIN config.standing_penalty csp ON (csp.id = usp.standing_penalty)
502           WHERE usr = match_user
503                 AND usp.org_unit IN ( SELECT * FROM unnest(context_org_list) )
504                 AND (usp.stop_date IS NULL or usp.stop_date > NOW())
505                 AND (csp.ignore_proximity IS NULL OR csp.ignore_proximity < item_prox
506                      OR csp.ignore_proximity < pickup_prox)
507                 AND csp.block_list LIKE '%' || hold_penalty || '%' LOOP
508
509         result.fail_part := standing_penalty.name;
510         result.success := FALSE;
511         done := TRUE;
512         RETURN NEXT result;
513     END LOOP;
514
515     IF hold_test.stop_blocked_user IS TRUE THEN
516         FOR standing_penalty IN
517             SELECT  DISTINCT csp.*
518               FROM  actor.usr_standing_penalty usp
519                     JOIN config.standing_penalty csp ON (csp.id = usp.standing_penalty)
520               WHERE usr = match_user
521                     AND usp.org_unit IN ( SELECT * FROM unnest(context_org_list) )
522                     AND (usp.stop_date IS NULL or usp.stop_date > NOW())
523                     AND csp.block_list LIKE '%CIRC%' LOOP
524     
525             result.fail_part := standing_penalty.name;
526             result.success := FALSE;
527             done := TRUE;
528             RETURN NEXT result;
529         END LOOP;
530     END IF;
531
532     IF hold_test.max_holds IS NOT NULL AND NOT retargetting THEN
533         SELECT    INTO hold_count COUNT(*)
534           FROM    action.hold_request
535           WHERE    usr = match_user
536             AND fulfillment_time IS NULL
537             AND cancel_time IS NULL
538             AND CASE WHEN hold_test.include_frozen_holds THEN TRUE ELSE frozen IS FALSE END;
539
540         IF hold_count >= hold_test.max_holds THEN
541             result.fail_part := 'config.hold_matrix_test.max_holds';
542             result.success := FALSE;
543             done := TRUE;
544             RETURN NEXT result;
545         END IF;
546     END IF;
547
548     IF item_object.age_protect IS NOT NULL THEN
549         SELECT INTO age_protect_object * FROM config.rule_age_hold_protect WHERE id = item_object.age_protect;
550         IF hold_test.distance_is_from_owner THEN
551             SELECT INTO use_active_date value FROM actor.org_unit_ancestor_setting('circ.holds.age_protect.active_date', item_cn_object.owning_lib);
552         ELSE
553             SELECT INTO use_active_date value FROM actor.org_unit_ancestor_setting('circ.holds.age_protect.active_date', item_object.circ_lib);
554         END IF;
555         IF use_active_date = 'true' THEN
556             age_protect_date := COALESCE(item_object.active_date, NOW());
557         ELSE
558             age_protect_date := item_object.create_date;
559         END IF;
560         IF age_protect_date + age_protect_object.age > NOW() THEN
561             IF hold_test.distance_is_from_owner THEN
562                 SELECT INTO item_cn_object * FROM asset.call_number WHERE id = item_object.call_number;
563                 SELECT INTO hold_transit_prox prox FROM actor.org_unit_proximity WHERE from_org = item_cn_object.owning_lib AND to_org = v_pickup_ou;
564             ELSE
565                 SELECT INTO hold_transit_prox prox FROM actor.org_unit_proximity WHERE from_org = item_object.circ_lib AND to_org = v_pickup_ou;
566             END IF;
567
568             IF hold_transit_prox > age_protect_object.prox THEN
569                 result.fail_part := 'config.rule_age_hold_protect.prox';
570                 result.success := FALSE;
571                 done := TRUE;
572                 RETURN NEXT result;
573             END IF;
574         END IF;
575     END IF;
576
577     IF NOT done THEN
578         RETURN NEXT result;
579     END IF;
580
581     RETURN;
582 END;
583 $func$ LANGUAGE plpgsql;
584
585 CREATE OR REPLACE FUNCTION action.item_user_circ_test( circ_ou INT, match_item BIGINT, match_user INT, renewal BOOL ) RETURNS SETOF action.circ_matrix_test_result AS $func$
586 DECLARE
587     user_object             actor.usr%ROWTYPE;
588     standing_penalty        config.standing_penalty%ROWTYPE;
589     item_object             asset.copy%ROWTYPE;
590     item_status_object      config.copy_status%ROWTYPE;
591     item_location_object    asset.copy_location%ROWTYPE;
592     result                  action.circ_matrix_test_result;
593     circ_test               action.found_circ_matrix_matchpoint;
594     circ_matchpoint         config.circ_matrix_matchpoint%ROWTYPE;
595     circ_limit_set          config.circ_limit_set%ROWTYPE;
596     hold_ratio              action.hold_stats%ROWTYPE;
597     penalty_type            TEXT;
598     items_out               INT;
599     context_org_list        INT[];
600     done                    BOOL := FALSE;
601     item_prox               INT;
602     home_prox               INT;
603 BEGIN
604     -- Assume success unless we hit a failure condition
605     result.success := TRUE;
606
607     -- Need user info to look up matchpoints
608     SELECT INTO user_object * FROM actor.usr WHERE id = match_user AND NOT deleted;
609
610     -- (Insta)Fail if we couldn't find the user
611     IF user_object.id IS NULL THEN
612         result.fail_part := 'no_user';
613         result.success := FALSE;
614         done := TRUE;
615         RETURN NEXT result;
616         RETURN;
617     END IF;
618
619     -- Need item info to look up matchpoints
620     SELECT INTO item_object * FROM asset.copy WHERE id = match_item AND NOT deleted;
621
622     -- (Insta)Fail if we couldn't find the item 
623     IF item_object.id IS NULL THEN
624         result.fail_part := 'no_item';
625         result.success := FALSE;
626         done := TRUE;
627         RETURN NEXT result;
628         RETURN;
629     END IF;
630
631     SELECT INTO circ_test * FROM action.find_circ_matrix_matchpoint(circ_ou, item_object, user_object, renewal);
632
633     circ_matchpoint             := circ_test.matchpoint;
634     result.matchpoint           := circ_matchpoint.id;
635     result.circulate            := circ_matchpoint.circulate;
636     result.duration_rule        := circ_matchpoint.duration_rule;
637     result.recurring_fine_rule  := circ_matchpoint.recurring_fine_rule;
638     result.max_fine_rule        := circ_matchpoint.max_fine_rule;
639     result.hard_due_date        := circ_matchpoint.hard_due_date;
640     result.renewals             := circ_matchpoint.renewals;
641     result.grace_period         := circ_matchpoint.grace_period;
642     result.buildrows            := circ_test.buildrows;
643
644     -- (Insta)Fail if we couldn't find a matchpoint
645     IF circ_test.success = false THEN
646         result.fail_part := 'no_matchpoint';
647         result.success := FALSE;
648         done := TRUE;
649         RETURN NEXT result;
650         RETURN;
651     END IF;
652
653     -- All failures before this point are non-recoverable
654     -- Below this point are possibly overridable failures
655
656     -- Fail if the user is barred
657     IF user_object.barred IS TRUE THEN
658         result.fail_part := 'actor.usr.barred';
659         result.success := FALSE;
660         done := TRUE;
661         RETURN NEXT result;
662     END IF;
663
664     -- Fail if the item can't circulate
665     IF item_object.circulate IS FALSE THEN
666         result.fail_part := 'asset.copy.circulate';
667         result.success := FALSE;
668         done := TRUE;
669         RETURN NEXT result;
670     END IF;
671
672     -- Fail if the item isn't in a circulateable status on a non-renewal
673     IF NOT renewal AND item_object.status NOT IN ( 0, 7, 8 ) THEN 
674         result.fail_part := 'asset.copy.status';
675         result.success := FALSE;
676         done := TRUE;
677         RETURN NEXT result;
678     -- Alternately, fail if the item isn't checked out on a renewal
679     ELSIF renewal AND item_object.status <> 1 THEN
680         result.fail_part := 'asset.copy.status';
681         result.success := FALSE;
682         done := TRUE;
683         RETURN NEXT result;
684     END IF;
685
686     -- Fail if the item can't circulate because of the shelving location
687     SELECT INTO item_location_object * FROM asset.copy_location WHERE id = item_object.location;
688     IF item_location_object.circulate IS FALSE THEN
689         result.fail_part := 'asset.copy_location.circulate';
690         result.success := FALSE;
691         done := TRUE;
692         RETURN NEXT result;
693     END IF;
694
695     -- Use Circ OU for penalties and such
696     SELECT INTO context_org_list ARRAY_AGG(id) FROM actor.org_unit_full_path( circ_ou );
697
698     -- Proximity of user's home_ou to circ_ou to see if penalties should be ignored.
699     SELECT INTO home_prox prox FROM actor.org_unit_proximity WHERE from_org = user_object.home_ou AND to_org = circ_ou;
700
701     -- Proximity of user's home_ou to item circ_lib to see if penalties should be ignored.
702     SELECT INTO item_prox prox FROM actor.org_unit_proximity WHERE from_org = user_object.home_ou AND to_org = item_object.circ_lib;
703
704     IF renewal THEN
705         penalty_type = '%RENEW%';
706     ELSE
707         penalty_type = '%CIRC%';
708     END IF;
709
710     FOR standing_penalty IN
711         SELECT  DISTINCT csp.*
712           FROM  actor.usr_standing_penalty usp
713                 JOIN config.standing_penalty csp ON (csp.id = usp.standing_penalty)
714           WHERE usr = match_user
715                 AND usp.org_unit IN ( SELECT * FROM unnest(context_org_list) )
716                 AND (usp.stop_date IS NULL or usp.stop_date > NOW())
717                 AND (csp.ignore_proximity IS NULL
718                      OR csp.ignore_proximity < home_prox
719                      OR csp.ignore_proximity < item_prox)
720                 AND csp.block_list LIKE penalty_type LOOP
721
722         result.fail_part := standing_penalty.name;
723         result.success := FALSE;
724         done := TRUE;
725         RETURN NEXT result;
726     END LOOP;
727
728     -- Fail if the test is set to hard non-circulating
729     IF circ_matchpoint.circulate IS FALSE THEN
730         result.fail_part := 'config.circ_matrix_test.circulate';
731         result.success := FALSE;
732         done := TRUE;
733         RETURN NEXT result;
734     END IF;
735
736     -- Fail if the total copy-hold ratio is too low
737     IF circ_matchpoint.total_copy_hold_ratio IS NOT NULL THEN
738         SELECT INTO hold_ratio * FROM action.copy_related_hold_stats(match_item);
739         IF hold_ratio.total_copy_ratio IS NOT NULL AND hold_ratio.total_copy_ratio < circ_matchpoint.total_copy_hold_ratio THEN
740             result.fail_part := 'config.circ_matrix_test.total_copy_hold_ratio';
741             result.success := FALSE;
742             done := TRUE;
743             RETURN NEXT result;
744         END IF;
745     END IF;
746
747     -- Fail if the available copy-hold ratio is too low
748     IF circ_matchpoint.available_copy_hold_ratio IS NOT NULL THEN
749         IF hold_ratio.hold_count IS NULL THEN
750             SELECT INTO hold_ratio * FROM action.copy_related_hold_stats(match_item);
751         END IF;
752         IF hold_ratio.available_copy_ratio IS NOT NULL AND hold_ratio.available_copy_ratio < circ_matchpoint.available_copy_hold_ratio THEN
753             result.fail_part := 'config.circ_matrix_test.available_copy_hold_ratio';
754             result.success := FALSE;
755             done := TRUE;
756             RETURN NEXT result;
757         END IF;
758     END IF;
759
760     -- Fail if the user has too many items out by defined limit sets
761     FOR circ_limit_set IN SELECT ccls.* FROM config.circ_limit_set ccls
762       JOIN config.circ_matrix_limit_set_map ccmlsm ON ccmlsm.limit_set = ccls.id
763       WHERE ccmlsm.active AND ( ccmlsm.matchpoint = circ_matchpoint.id OR
764         ( ccmlsm.matchpoint IN (SELECT * FROM unnest(result.buildrows)) AND ccmlsm.fallthrough )
765         ) LOOP
766             IF circ_limit_set.items_out > 0 AND NOT renewal THEN
767                 SELECT INTO context_org_list ARRAY_AGG(aou.id)
768                   FROM actor.org_unit_full_path( circ_ou ) aou
769                     JOIN actor.org_unit_type aout ON aou.ou_type = aout.id
770                   WHERE aout.depth >= circ_limit_set.depth;
771                 IF circ_limit_set.global THEN
772                     WITH RECURSIVE descendant_depth AS (
773                         SELECT  ou.id,
774                             ou.parent_ou
775                         FROM  actor.org_unit ou
776                         WHERE ou.id IN (SELECT * FROM unnest(context_org_list))
777                             UNION
778                         SELECT  ou.id,
779                             ou.parent_ou
780                         FROM  actor.org_unit ou
781                             JOIN descendant_depth ot ON (ot.id = ou.parent_ou)
782                     ) SELECT INTO context_org_list ARRAY_AGG(ou.id) FROM actor.org_unit ou JOIN descendant_depth USING (id);
783                 END IF;
784                 SELECT INTO items_out COUNT(DISTINCT circ.id)
785                   FROM action.circulation circ
786                     JOIN asset.copy copy ON (copy.id = circ.target_copy)
787                     LEFT JOIN action.circulation_limit_group_map aclgm ON (circ.id = aclgm.circ)
788                   WHERE circ.usr = match_user
789                     AND circ.circ_lib IN (SELECT * FROM unnest(context_org_list))
790                     AND circ.checkin_time IS NULL
791                     AND (circ.stop_fines IN ('MAXFINES','LONGOVERDUE') OR circ.stop_fines IS NULL)
792                     AND (copy.circ_modifier IN (SELECT circ_mod FROM config.circ_limit_set_circ_mod_map WHERE limit_set = circ_limit_set.id)
793                         OR copy.location IN (SELECT copy_loc FROM config.circ_limit_set_copy_loc_map WHERE limit_set = circ_limit_set.id)
794                         OR aclgm.limit_group IN (SELECT limit_group FROM config.circ_limit_set_group_map WHERE limit_set = circ_limit_set.id)
795                     );
796                 IF items_out >= circ_limit_set.items_out THEN
797                     result.fail_part := 'config.circ_matrix_circ_mod_test';
798                     result.success := FALSE;
799                     done := TRUE;
800                     RETURN NEXT result;
801                 END IF;
802             END IF;
803             SELECT INTO result.limit_groups result.limit_groups || ARRAY_AGG(limit_group) FROM config.circ_limit_set_group_map WHERE limit_set = circ_limit_set.id AND NOT check_only;
804     END LOOP;
805
806     -- If we passed everything, return the successful matchpoint
807     IF NOT done THEN
808         RETURN NEXT result;
809     END IF;
810
811     RETURN;
812 END;
813 $func$ LANGUAGE plpgsql;
814
815 SELECT evergreen.upgrade_deps_block_check('0952', :eg_version); --miker/kmlussier/gmcharlt
816
817 INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, browse_field, facet_field, facet_xpath, joiner ) VALUES
818     (33, 'identifier', 'genre', oils_i18n_gettext(33, 'Genre', 'cmf', 'label'), 'marcxml', $$//marc:datafield[@tag='655']$$, FALSE, TRUE, $$//*[local-name()='subfield' and contains('abvxyz',@code)]$$, ' -- ' ); -- /* to fool vim */;
819
820 INSERT INTO config.metabib_field_index_norm_map (field,norm)
821     SELECT  m.id,
822             i.id
823       FROM  config.metabib_field m,
824         config.index_normalizer i
825       WHERE i.func IN ('search_normalize','split_date_range')
826             AND m.id IN (33);
827
828 SELECT evergreen.upgrade_deps_block_check('0953', :eg_version);
829
830 CREATE OR REPLACE FUNCTION unapi.bre (
831     obj_id BIGINT,
832     format TEXT,
833     ename TEXT,
834     includes TEXT[],
835     org TEXT,
836     depth INT DEFAULT NULL,
837     slimit HSTORE DEFAULT NULL,
838     soffset HSTORE DEFAULT NULL,
839     include_xmlns BOOL DEFAULT TRUE,
840     pref_lib INT DEFAULT NULL
841 )
842 RETURNS XML AS $F$
843 DECLARE
844     me      biblio.record_entry%ROWTYPE;
845     layout  unapi.bre_output_layout%ROWTYPE;
846     xfrm    config.xml_transform%ROWTYPE;
847     ouid    INT;
848     tmp_xml TEXT;
849     top_el  TEXT;
850     output  XML;
851     hxml    XML;
852     axml    XML;
853     source  XML;
854 BEGIN
855
856     IF org = '-' OR org IS NULL THEN
857         SELECT shortname INTO org FROM evergreen.org_top();
858     END IF;
859
860     SELECT id INTO ouid FROM actor.org_unit WHERE shortname = org;
861
862     IF ouid IS NULL THEN
863         RETURN NULL::XML;
864     END IF;
865
866     IF format = 'holdings_xml' THEN -- the special case
867         output := unapi.holdings_xml( obj_id, ouid, org, depth, includes, slimit, soffset, include_xmlns);
868         RETURN output;
869     END IF;
870
871     SELECT * INTO layout FROM unapi.bre_output_layout WHERE name = format;
872
873     IF layout.name IS NULL THEN
874         RETURN NULL::XML;
875     END IF;
876
877     SELECT * INTO xfrm FROM config.xml_transform WHERE name = layout.transform;
878
879     SELECT * INTO me FROM biblio.record_entry WHERE id = obj_id;
880
881     -- grab bib_source, if any
882     IF ('cbs' = ANY (includes) AND me.source IS NOT NULL) THEN
883         source := unapi.cbs(me.source,NULL,NULL,NULL,NULL);
884     ELSE
885         source := NULL::XML;
886     END IF;
887
888     -- grab SVF if we need them
889     IF ('mra' = ANY (includes)) THEN 
890         axml := unapi.mra(obj_id,NULL,NULL,NULL,NULL);
891     ELSE
892         axml := NULL::XML;
893     END IF;
894
895     -- grab holdings if we need them
896     IF ('holdings_xml' = ANY (includes)) THEN 
897         hxml := unapi.holdings_xml(obj_id, ouid, org, depth, evergreen.array_remove_item_by_value(includes,'holdings_xml'), slimit, soffset, include_xmlns, pref_lib);
898     ELSE
899         hxml := NULL::XML;
900     END IF;
901
902
903     -- generate our item node
904
905
906     IF format = 'marcxml' THEN
907         tmp_xml := me.marc;
908         IF tmp_xml !~ E'<marc:' THEN -- If we're not using the prefixed namespace in this record, then remove all declarations of it
909            tmp_xml := REGEXP_REPLACE(tmp_xml, ' xmlns:marc="http://www.loc.gov/MARC21/slim"', '', 'g');
910         END IF; 
911     ELSE
912         tmp_xml := oils_xslt_process(me.marc, xfrm.xslt)::XML;
913     END IF;
914
915     top_el := REGEXP_REPLACE(tmp_xml, E'^.*?<((?:\\S+:)?' || layout.holdings_element || ').*$', E'\\1');
916
917     IF source IS NOT NULL THEN
918         tmp_xml := REGEXP_REPLACE(tmp_xml, '</' || top_el || '>(.*?)$', source || '</' || top_el || E'>\\1');
919     END IF;
920
921     IF axml IS NOT NULL THEN 
922         tmp_xml := REGEXP_REPLACE(tmp_xml, '</' || top_el || '>(.*?)$', axml || '</' || top_el || E'>\\1');
923     END IF;
924
925     IF hxml IS NOT NULL THEN -- XXX how do we configure the holdings position?
926         tmp_xml := REGEXP_REPLACE(tmp_xml, '</' || top_el || '>(.*?)$', hxml || '</' || top_el || E'>\\1');
927     END IF;
928
929     IF ('bre.unapi' = ANY (includes)) THEN 
930         output := REGEXP_REPLACE(
931             tmp_xml,
932             '</' || top_el || '>(.*?)',
933             XMLELEMENT(
934                 name abbr,
935                 XMLATTRIBUTES(
936                     'http://www.w3.org/1999/xhtml' AS xmlns,
937                     'unapi-id' AS class,
938                     'tag:open-ils.org:U2@bre/' || obj_id || '/' || org AS title
939                 )
940             )::TEXT || '</' || top_el || E'>\\1'
941         );
942     ELSE
943         output := tmp_xml;
944     END IF;
945
946     IF ('bre.extern' = ANY (includes)) THEN 
947         output := REGEXP_REPLACE(
948             tmp_xml,
949             '</' || top_el || '>(.*?)',
950             XMLELEMENT(
951                 name extern,
952                 XMLATTRIBUTES(
953                     'http://open-ils.org/spec/biblio/v1' AS xmlns,
954                     me.creator AS creator,
955                     me.editor AS editor,
956                     me.create_date AS create_date,
957                     me.edit_date AS edit_date,
958                     me.quality AS quality,
959                     me.fingerprint AS fingerprint,
960                     me.tcn_source AS tcn_source,
961                     me.tcn_value AS tcn_value,
962                     me.owner AS owner,
963                     me.share_depth AS share_depth,
964                     me.active AS active,
965                     me.deleted AS deleted
966                 )
967             )::TEXT || '</' || top_el || E'>\\1'
968         );
969     ELSE
970         output := tmp_xml;
971     END IF;
972
973     output := REGEXP_REPLACE(output::TEXT,E'>\\s+<','><','gs')::XML;
974     RETURN output;
975 END;
976 $F$ LANGUAGE PLPGSQL STABLE;
977
978 SELECT evergreen.upgrade_deps_block_check('0954', :eg_version);
979
980 ALTER TABLE acq.fund_debit 
981     ADD COLUMN invoice_entry INTEGER 
982         REFERENCES acq.invoice_entry (id)
983         ON DELETE SET NULL;
984
985 CREATE INDEX fund_debit_invoice_entry_idx ON acq.fund_debit (invoice_entry);
986 CREATE INDEX lineitem_detail_fund_debit_idx ON acq.lineitem_detail (fund_debit);
987
988 SELECT evergreen.upgrade_deps_block_check('0955', :eg_version);
989
990 UPDATE config.org_unit_setting_type
991 SET description = 'Regular expression defining the password format.  Note: Be sure to update the update_password_msg.tt2 TPAC template with a user-friendly description of your password strength requirements.'
992 WHERE NAME = 'global.password_regex';
993
994 SELECT evergreen.upgrade_deps_block_check('0956', :eg_version);
995
996 ALTER TABLE money.credit_card_payment 
997     DROP COLUMN cc_type,
998     DROP COLUMN expire_month,
999     DROP COLUMN expire_year,
1000     DROP COLUMN cc_first_name,
1001     DROP COLUMN cc_last_name;
1002
1003 SELECT evergreen.upgrade_deps_block_check('0957', :eg_version);
1004
1005 -- Remove references to dropped CC payment columns in the print/email 
1006 -- payment receipt templates, but only if the in-db template matches 
1007 -- the stock template.
1008 -- The actual diff here is only about 8 lines.
1009
1010 UPDATE action_trigger.event_definition SET template = 
1011 $$
1012 [%- USE date -%]
1013 [%- SET user = target.0.xact.usr -%]
1014 To: [%- params.recipient_email || user.email %]
1015 From: [%- params.sender_email || default_sender %]
1016 Subject: Payment Receipt
1017
1018 [% date.format -%]
1019 [%- SET xact_mp_hash = {} -%]
1020 [%- FOR mp IN target %][%# Template is hooked around payments, but let us make the receipt focused on transactions -%]
1021     [%- SET xact_id = mp.xact.id -%]
1022     [%- IF ! xact_mp_hash.defined( xact_id ) -%][%- xact_mp_hash.$xact_id = { 'xact' => mp.xact, 'payments' => [] } -%][%- END -%]
1023     [%- xact_mp_hash.$xact_id.payments.push(mp) -%]
1024 [%- END -%]
1025 [%- FOR xact_id IN xact_mp_hash.keys.sort -%]
1026     [%- SET xact = xact_mp_hash.$xact_id.xact %]
1027 Transaction ID: [% xact_id %]
1028     [% IF xact.circulation %][% helpers.get_copy_bib_basics(xact.circulation.target_copy).title %]
1029     [% ELSE %]Miscellaneous
1030     [% END %]
1031     Line item billings:
1032         [%- SET mb_type_hash = {} -%]
1033         [%- FOR mb IN xact.billings %][%# Group billings by their btype -%]
1034             [%- IF mb.voided == 'f' -%]
1035                 [%- SET mb_type = mb.btype.id -%]
1036                 [%- IF ! mb_type_hash.defined( mb_type ) -%][%- mb_type_hash.$mb_type = { 'sum' => 0.00, 'billings' => [] } -%][%- END -%]
1037                 [%- IF ! mb_type_hash.$mb_type.defined( 'first_ts' ) -%][%- mb_type_hash.$mb_type.first_ts = mb.billing_ts -%][%- END -%]
1038                 [%- mb_type_hash.$mb_type.last_ts = mb.billing_ts -%]
1039                 [%- mb_type_hash.$mb_type.sum = mb_type_hash.$mb_type.sum + mb.amount -%]
1040                 [%- mb_type_hash.$mb_type.billings.push( mb ) -%]
1041             [%- END -%]
1042         [%- END -%]
1043         [%- FOR mb_type IN mb_type_hash.keys.sort -%]
1044             [%- IF mb_type == 1 %][%-# Consolidated view of overdue billings -%]
1045                 $[% mb_type_hash.$mb_type.sum %] for [% mb_type_hash.$mb_type.billings.0.btype.name %] 
1046                     on [% mb_type_hash.$mb_type.first_ts %] through [% mb_type_hash.$mb_type.last_ts %]
1047             [%- ELSE -%][%# all other billings show individually %]
1048                 [% FOR mb IN mb_type_hash.$mb_type.billings %]
1049                     $[% mb.amount %] for [% mb.btype.name %] on [% mb.billing_ts %] [% mb.note %]
1050                 [% END %]
1051             [% END %]
1052         [% END %]
1053     Line item payments:
1054         [% FOR mp IN xact_mp_hash.$xact_id.payments %]
1055             Payment ID: [% mp.id %]
1056                 Paid [% mp.amount %] via [% SWITCH mp.payment_type -%]
1057                     [% CASE "cash_payment" %]cash
1058                     [% CASE "check_payment" %]check
1059                     [% CASE "credit_card_payment" %]credit card
1060                     [%- IF mp.credit_card_payment.cc_number %] ([% mp.credit_card_payment.cc_number %])[% END %]
1061                     [% CASE "credit_payment" %]credit
1062                     [% CASE "forgive_payment" %]forgiveness
1063                     [% CASE "goods_payment" %]goods
1064                     [% CASE "work_payment" %]work
1065                 [%- END %] on [% mp.payment_ts %] [% mp.note %]
1066         [% END %]
1067 [% END %]
1068 $$
1069
1070 WHERE id = 29 AND template =
1071
1072 $$
1073 [%- USE date -%]
1074 [%- SET user = target.0.xact.usr -%]
1075 To: [%- params.recipient_email || user.email %]
1076 From: [%- params.sender_email || default_sender %]
1077 Subject: Payment Receipt
1078
1079 [% date.format -%]
1080 [%- SET xact_mp_hash = {} -%]
1081 [%- FOR mp IN target %][%# Template is hooked around payments, but let us make the receipt focused on transactions -%]
1082     [%- SET xact_id = mp.xact.id -%]
1083     [%- IF ! xact_mp_hash.defined( xact_id ) -%][%- xact_mp_hash.$xact_id = { 'xact' => mp.xact, 'payments' => [] } -%][%- END -%]
1084     [%- xact_mp_hash.$xact_id.payments.push(mp) -%]
1085 [%- END -%]
1086 [%- FOR xact_id IN xact_mp_hash.keys.sort -%]
1087     [%- SET xact = xact_mp_hash.$xact_id.xact %]
1088 Transaction ID: [% xact_id %]
1089     [% IF xact.circulation %][% helpers.get_copy_bib_basics(xact.circulation.target_copy).title %]
1090     [% ELSE %]Miscellaneous
1091     [% END %]
1092     Line item billings:
1093         [%- SET mb_type_hash = {} -%]
1094         [%- FOR mb IN xact.billings %][%# Group billings by their btype -%]
1095             [%- IF mb.voided == 'f' -%]
1096                 [%- SET mb_type = mb.btype.id -%]
1097                 [%- IF ! mb_type_hash.defined( mb_type ) -%][%- mb_type_hash.$mb_type = { 'sum' => 0.00, 'billings' => [] } -%][%- END -%]
1098                 [%- IF ! mb_type_hash.$mb_type.defined( 'first_ts' ) -%][%- mb_type_hash.$mb_type.first_ts = mb.billing_ts -%][%- END -%]
1099                 [%- mb_type_hash.$mb_type.last_ts = mb.billing_ts -%]
1100                 [%- mb_type_hash.$mb_type.sum = mb_type_hash.$mb_type.sum + mb.amount -%]
1101                 [%- mb_type_hash.$mb_type.billings.push( mb ) -%]
1102             [%- END -%]
1103         [%- END -%]
1104         [%- FOR mb_type IN mb_type_hash.keys.sort -%]
1105             [%- IF mb_type == 1 %][%-# Consolidated view of overdue billings -%]
1106                 $[% mb_type_hash.$mb_type.sum %] for [% mb_type_hash.$mb_type.billings.0.btype.name %] 
1107                     on [% mb_type_hash.$mb_type.first_ts %] through [% mb_type_hash.$mb_type.last_ts %]
1108             [%- ELSE -%][%# all other billings show individually %]
1109                 [% FOR mb IN mb_type_hash.$mb_type.billings %]
1110                     $[% mb.amount %] for [% mb.btype.name %] on [% mb.billing_ts %] [% mb.note %]
1111                 [% END %]
1112             [% END %]
1113         [% END %]
1114     Line item payments:
1115         [% FOR mp IN xact_mp_hash.$xact_id.payments %]
1116             Payment ID: [% mp.id %]
1117                 Paid [% mp.amount %] via [% SWITCH mp.payment_type -%]
1118                     [% CASE "cash_payment" %]cash
1119                     [% CASE "check_payment" %]check
1120                     [% CASE "credit_card_payment" %]credit card (
1121                         [%- SET cc_chunks = mp.credit_card_payment.cc_number.replace(' ','').chunk(4); -%]
1122                         [%- cc_chunks.slice(0, -1+cc_chunks.max).join.replace('\S','X') -%] 
1123                         [% cc_chunks.last -%]
1124                         exp [% mp.credit_card_payment.expire_month %]/[% mp.credit_card_payment.expire_year -%]
1125                     )
1126                     [% CASE "credit_payment" %]credit
1127                     [% CASE "forgive_payment" %]forgiveness
1128                     [% CASE "goods_payment" %]goods
1129                     [% CASE "work_payment" %]work
1130                 [%- END %] on [% mp.payment_ts %] [% mp.note %]
1131         [% END %]
1132 [% END %]
1133 $$;
1134
1135
1136 UPDATE action_trigger.event_definition SET template = 
1137 $$
1138 [%- USE date -%][%- SET user = target.0.xact.usr -%]
1139 <div style="li { padding: 8px; margin 5px; }">
1140     <div>[% date.format %]</div><br/>
1141     <ol>
1142     [% SET xact_mp_hash = {} %]
1143     [% FOR mp IN target %][%# Template is hooked around payments, but let us make the receipt focused on transactions %]
1144         [% SET xact_id = mp.xact.id %]
1145         [% IF ! xact_mp_hash.defined( xact_id ) %][% xact_mp_hash.$xact_id = { 'xact' => mp.xact, 'payments' => [] } %][% END %]
1146         [% xact_mp_hash.$xact_id.payments.push(mp) %]
1147     [% END %]
1148     [% FOR xact_id IN xact_mp_hash.keys.sort %]
1149         [% SET xact = xact_mp_hash.$xact_id.xact %]
1150         <li>Transaction ID: [% xact_id %]
1151             [% IF xact.circulation %][% helpers.get_copy_bib_basics(xact.circulation.target_copy).title %]
1152             [% ELSE %]Miscellaneous
1153             [% END %]
1154             Line item billings:<ol>
1155                 [% SET mb_type_hash = {} %]
1156                 [% FOR mb IN xact.billings %][%# Group billings by their btype %]
1157                     [% IF mb.voided == 'f' %]
1158                         [% SET mb_type = mb.btype.id %]
1159                         [% IF ! mb_type_hash.defined( mb_type ) %][% mb_type_hash.$mb_type = { 'sum' => 0.00, 'billings' => [] } %][% END %]
1160                         [% IF ! mb_type_hash.$mb_type.defined( 'first_ts' ) %][% mb_type_hash.$mb_type.first_ts = mb.billing_ts %][% END %]
1161                         [% mb_type_hash.$mb_type.last_ts = mb.billing_ts %]
1162                         [% mb_type_hash.$mb_type.sum = mb_type_hash.$mb_type.sum + mb.amount %]
1163                         [% mb_type_hash.$mb_type.billings.push( mb ) %]
1164                     [% END %]
1165                 [% END %]
1166                 [% FOR mb_type IN mb_type_hash.keys.sort %]
1167                     <li>[% IF mb_type == 1 %][%# Consolidated view of overdue billings %]
1168                         $[% mb_type_hash.$mb_type.sum %] for [% mb_type_hash.$mb_type.billings.0.btype.name %] 
1169                             on [% mb_type_hash.$mb_type.first_ts %] through [% mb_type_hash.$mb_type.last_ts %]
1170                     [% ELSE %][%# all other billings show individually %]
1171                         [% FOR mb IN mb_type_hash.$mb_type.billings %]
1172                             $[% mb.amount %] for [% mb.btype.name %] on [% mb.billing_ts %] [% mb.note %]
1173                         [% END %]
1174                     [% END %]</li>
1175                 [% END %]
1176             </ol>
1177             Line item payments:<ol>
1178                 [% FOR mp IN xact_mp_hash.$xact_id.payments %]
1179                     <li>Payment ID: [% mp.id %]
1180                         Paid [% mp.amount %] via [% SWITCH mp.payment_type -%]
1181                             [% CASE "cash_payment" %]cash
1182                             [% CASE "check_payment" %]check
1183                             [% CASE "credit_card_payment" %]credit card
1184                             [%- IF mp.credit_card_payment.cc_number %] ([% mp.credit_card_payment.cc_number %])[% END %]
1185                             [% CASE "credit_payment" %]credit
1186                             [% CASE "forgive_payment" %]forgiveness
1187                             [% CASE "goods_payment" %]goods
1188                             [% CASE "work_payment" %]work
1189                         [%- END %] on [% mp.payment_ts %] [% mp.note %]
1190                     </li>
1191                 [% END %]
1192             </ol>
1193         </li>
1194     [% END %]
1195     </ol>
1196 </div>
1197 $$
1198
1199 WHERE id = 30 AND template =
1200
1201 $$
1202 [%- USE date -%][%- SET user = target.0.xact.usr -%]
1203 <div style="li { padding: 8px; margin 5px; }">
1204     <div>[% date.format %]</div><br/>
1205     <ol>
1206     [% SET xact_mp_hash = {} %]
1207     [% FOR mp IN target %][%# Template is hooked around payments, but let us make the receipt focused on transactions %]
1208         [% SET xact_id = mp.xact.id %]
1209         [% IF ! xact_mp_hash.defined( xact_id ) %][% xact_mp_hash.$xact_id = { 'xact' => mp.xact, 'payments' => [] } %][% END %]
1210         [% xact_mp_hash.$xact_id.payments.push(mp) %]
1211     [% END %]
1212     [% FOR xact_id IN xact_mp_hash.keys.sort %]
1213         [% SET xact = xact_mp_hash.$xact_id.xact %]
1214         <li>Transaction ID: [% xact_id %]
1215             [% IF xact.circulation %][% helpers.get_copy_bib_basics(xact.circulation.target_copy).title %]
1216             [% ELSE %]Miscellaneous
1217             [% END %]
1218             Line item billings:<ol>
1219                 [% SET mb_type_hash = {} %]
1220                 [% FOR mb IN xact.billings %][%# Group billings by their btype %]
1221                     [% IF mb.voided == 'f' %]
1222                         [% SET mb_type = mb.btype.id %]
1223                         [% IF ! mb_type_hash.defined( mb_type ) %][% mb_type_hash.$mb_type = { 'sum' => 0.00, 'billings' => [] } %][% END %]
1224                         [% IF ! mb_type_hash.$mb_type.defined( 'first_ts' ) %][% mb_type_hash.$mb_type.first_ts = mb.billing_ts %][% END %]
1225                         [% mb_type_hash.$mb_type.last_ts = mb.billing_ts %]
1226                         [% mb_type_hash.$mb_type.sum = mb_type_hash.$mb_type.sum + mb.amount %]
1227                         [% mb_type_hash.$mb_type.billings.push( mb ) %]
1228                     [% END %]
1229                 [% END %]
1230                 [% FOR mb_type IN mb_type_hash.keys.sort %]
1231                     <li>[% IF mb_type == 1 %][%# Consolidated view of overdue billings %]
1232                         $[% mb_type_hash.$mb_type.sum %] for [% mb_type_hash.$mb_type.billings.0.btype.name %] 
1233                             on [% mb_type_hash.$mb_type.first_ts %] through [% mb_type_hash.$mb_type.last_ts %]
1234                     [% ELSE %][%# all other billings show individually %]
1235                         [% FOR mb IN mb_type_hash.$mb_type.billings %]
1236                             $[% mb.amount %] for [% mb.btype.name %] on [% mb.billing_ts %] [% mb.note %]
1237                         [% END %]
1238                     [% END %]</li>
1239                 [% END %]
1240             </ol>
1241             Line item payments:<ol>
1242                 [% FOR mp IN xact_mp_hash.$xact_id.payments %]
1243                     <li>Payment ID: [% mp.id %]
1244                         Paid [% mp.amount %] via [% SWITCH mp.payment_type -%]
1245                             [% CASE "cash_payment" %]cash
1246                             [% CASE "check_payment" %]check
1247                             [% CASE "credit_card_payment" %]credit card (
1248                                 [%- SET cc_chunks = mp.credit_card_payment.cc_number.replace(' ','').chunk(4); -%]
1249                                 [%- cc_chunks.slice(0, -1+cc_chunks.max).join.replace('\S','X') -%] 
1250                                 [% cc_chunks.last -%]
1251                                 exp [% mp.credit_card_payment.expire_month %]/[% mp.credit_card_payment.expire_year -%]
1252                             )
1253                             [% CASE "credit_payment" %]credit
1254                             [% CASE "forgive_payment" %]forgiveness
1255                             [% CASE "goods_payment" %]goods
1256                             [% CASE "work_payment" %]work
1257                         [%- END %] on [% mp.payment_ts %] [% mp.note %]
1258                     </li>
1259                 [% END %]
1260             </ol>
1261         </li>
1262     [% END %]
1263     </ol>
1264 </div>
1265 $$;
1266
1267
1268 SELECT evergreen.upgrade_deps_block_check('0958', :eg_version);
1269
1270 CREATE OR REPLACE FUNCTION search.facets_for_record_set(ignore_facet_classes TEXT[], hits BIGINT[]) RETURNS TABLE (id INT, value TEXT, count BIGINT) AS $$
1271     SELECT id, value, count FROM (
1272         SELECT mfae.field AS id,
1273                mfae.value,
1274                COUNT(DISTINCT mmrsm.source),
1275                row_number() OVER (
1276                 PARTITION BY mfae.field ORDER BY COUNT(distinct mmrsm.source) DESC
1277                ) AS rownum
1278         FROM metabib.facet_entry mfae
1279         JOIN metabib.metarecord_source_map mmrsm ON (mfae.source = mmrsm.source)
1280         JOIN config.metabib_field cmf ON (cmf.id = mfae.field)
1281         WHERE mmrsm.source IN (SELECT * FROM unnest($2))
1282         AND cmf.facet_field
1283         AND cmf.field_class NOT IN (SELECT * FROM unnest($1))
1284         GROUP by 1, 2
1285     ) all_facets
1286     WHERE rownum <= (SELECT COALESCE((SELECT value::INT FROM config.global_flag WHERE name = 'search.max_facets_per_field' AND enabled), 1000));
1287 $$ LANGUAGE SQL;
1288
1289 CREATE OR REPLACE FUNCTION search.facets_for_metarecord_set(ignore_facet_classes TEXT[], hits BIGINT[]) RETURNS TABLE (id INT, value TEXT, count BIGINT) AS $$
1290     SELECT id, value, count FROM (
1291         SELECT mfae.field AS id,
1292                mfae.value,
1293                COUNT(DISTINCT mmrsm.metarecord),
1294                row_number() OVER (
1295                 PARTITION BY mfae.field ORDER BY COUNT(distinct mmrsm.metarecord) DESC
1296                ) AS rownum
1297         FROM metabib.facet_entry mfae
1298         JOIN metabib.metarecord_source_map mmrsm ON (mfae.source = mmrsm.source)
1299         JOIN config.metabib_field cmf ON (cmf.id = mfae.field)
1300         WHERE mmrsm.metarecord IN (SELECT * FROM unnest($2))
1301         AND cmf.facet_field
1302         AND cmf.field_class NOT IN (SELECT * FROM unnest($1))
1303         GROUP by 1, 2
1304     ) all_facets
1305     WHERE rownum <= (SELECT COALESCE((SELECT value::INT FROM config.global_flag WHERE name = 'search.max_facets_per_field' AND enabled), 1000));
1306 $$ LANGUAGE SQL;
1307
1308 INSERT INTO config.global_flag (name, value, label, enabled)
1309     VALUES (
1310         'search.max_facets_per_field',
1311         '1000',
1312         oils_i18n_gettext(
1313             'search.max_facets_per_field',
1314             'Search: maximum number of facet values to retrieve for each facet field',
1315             'cgf',
1316             'label'
1317         ),
1318         TRUE
1319     );
1320
1321 SELECT evergreen.upgrade_deps_block_check('0960', :eg_version); 
1322
1323 CREATE TABLE action.usr_circ_history (
1324     id           BIGSERIAL PRIMARY KEY,
1325     usr          INTEGER NOT NULL REFERENCES actor.usr(id)
1326                  DEFERRABLE INITIALLY DEFERRED,
1327     xact_start   TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
1328     target_copy  BIGINT NOT NULL,
1329     due_date     TIMESTAMP WITH TIME ZONE NOT NULL,
1330     checkin_time TIMESTAMP WITH TIME ZONE,
1331     source_circ  BIGINT REFERENCES action.circulation(id)
1332                  ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED
1333 );
1334
1335 CREATE OR REPLACE FUNCTION action.maintain_usr_circ_history() 
1336     RETURNS TRIGGER AS $FUNK$
1337 DECLARE
1338     cur_circ  BIGINT;
1339     first_circ BIGINT;
1340 BEGIN                                                                          
1341
1342     -- Any retention value signifies history is enabled.
1343     -- This assumes that clearing these values via external 
1344     -- process deletes the action.usr_circ_history rows.
1345     -- TODO: replace these settings w/ a single bool setting?
1346     PERFORM 1 FROM actor.usr_setting 
1347         WHERE usr = NEW.usr AND value IS NOT NULL AND name IN (
1348             'history.circ.retention_age', 
1349             'history.circ.retention_start'
1350         );
1351
1352     IF NOT FOUND THEN
1353         RETURN NEW;
1354     END IF;
1355
1356     IF TG_OP = 'INSERT' AND NEW.parent_circ IS NULL THEN
1357         -- Starting a new circulation.  Insert the history row.
1358         INSERT INTO action.usr_circ_history 
1359             (usr, xact_start, target_copy, due_date, source_circ)
1360         VALUES (
1361             NEW.usr, 
1362             NEW.xact_start, 
1363             NEW.target_copy, 
1364             NEW.due_date, 
1365             NEW.id
1366         );
1367
1368         RETURN NEW;
1369     END IF;
1370
1371     -- find the first and last circs in the circ chain 
1372     -- for the currently modified circ.
1373     FOR cur_circ IN SELECT id FROM action.circ_chain(NEW.id) LOOP
1374         IF first_circ IS NULL THEN
1375             first_circ := cur_circ;
1376             CONTINUE;
1377         END IF;
1378         -- Allow the loop to continue so that at as the loop
1379         -- completes cur_circ points to the final circulation.
1380     END LOOP;
1381
1382     IF NEW.id <> cur_circ THEN
1383         -- Modifying an intermediate circ.  Ignore it.
1384         RETURN NEW;
1385     END IF;
1386
1387     -- Update the due_date/checkin_time on the history row if the current 
1388     -- circ is the last circ in the chain and an update is warranted.
1389
1390     UPDATE action.usr_circ_history 
1391         SET 
1392             due_date = NEW.due_date,
1393             checkin_time = NEW.checkin_time
1394         WHERE 
1395             source_circ = first_circ 
1396             AND (
1397                 due_date <> NEW.due_date OR (
1398                     (checkin_time IS NULL AND NEW.checkin_time IS NOT NULL) OR
1399                     (checkin_time IS NOT NULL AND NEW.checkin_time IS NULL) OR
1400                     (checkin_time <> NEW.checkin_time)
1401                 )
1402             );
1403     RETURN NEW;
1404 END;                                                                           
1405 $FUNK$ LANGUAGE PLPGSQL; 
1406
1407 CREATE TRIGGER maintain_usr_circ_history_tgr 
1408     AFTER INSERT OR UPDATE ON action.circulation 
1409     FOR EACH ROW EXECUTE PROCEDURE action.maintain_usr_circ_history();
1410
1411 UPDATE action_trigger.hook 
1412     SET core_type = 'auch' 
1413     WHERE key ~ '^circ.format.history.'; 
1414
1415 UPDATE action_trigger.event_definition SET template = 
1416 $$
1417 [%- USE date -%]
1418 [%- SET user = target.0.usr -%]
1419 To: [%- params.recipient_email || user.email %]
1420 From: [%- params.sender_email || default_sender %]
1421 Subject: Circulation History
1422
1423     [% FOR circ IN target %]
1424             [% helpers.get_copy_bib_basics(circ.target_copy.id).title %]
1425             Barcode: [% circ.target_copy.barcode %]
1426             Checked Out: [% date.format(helpers.format_date(circ.xact_start), '%Y-%m-%d') %]
1427             Due Date: [% date.format(helpers.format_date(circ.due_date), '%Y-%m-%d') %]
1428             Returned: [%
1429                 date.format(
1430                     helpers.format_date(circ.checkin_time), '%Y-%m-%d') 
1431                     IF circ.checkin_time; 
1432             %]
1433     [% END %]
1434 $$
1435 WHERE id = 25 AND template = 
1436 $$
1437 [%- USE date -%]
1438 [%- SET user = target.0.usr -%]
1439 To: [%- params.recipient_email || user.email %]
1440 From: [%- params.sender_email || default_sender %]
1441 Subject: Circulation History
1442
1443     [% FOR circ IN target %]
1444             [% helpers.get_copy_bib_basics(circ.target_copy.id).title %]
1445             Barcode: [% circ.target_copy.barcode %]
1446             Checked Out: [% date.format(helpers.format_date(circ.xact_start), '%Y-%m-%d') %]
1447             Due Date: [% date.format(helpers.format_date(circ.due_date), '%Y-%m-%d') %]
1448             Returned: [% date.format(helpers.format_date(circ.checkin_time), '%Y-%m-%d') %]
1449     [% END %]
1450 $$;
1451
1452 -- avoid TT undef date errors
1453 UPDATE action_trigger.event_definition SET template = 
1454 $$
1455 [%- USE date -%]
1456 <div>
1457     <style> li { padding: 8px; margin 5px; }</style>
1458     <div>[% date.format %]</div>
1459     <br/>
1460
1461     [% user.family_name %], [% user.first_given_name %]
1462     <ol>
1463     [% FOR circ IN target %]
1464         <li>
1465             <div>[% helpers.get_copy_bib_basics(circ.target_copy.id).title %]</div>
1466             <div>Barcode: [% circ.target_copy.barcode %]</div>
1467             <div>Checked Out: [% date.format(helpers.format_date(circ.xact_start), '%Y-%m-%d') %]</div>
1468             <div>Due Date: [% date.format(helpers.format_date(circ.due_date), '%Y-%m-%d') %]</div>
1469             <div>Returned: [%
1470                 date.format(
1471                     helpers.format_date(circ.checkin_time), '%Y-%m-%d') 
1472                     IF circ.checkin_time; -%]
1473             </div>
1474         </li>
1475     [% END %]
1476     </ol>
1477 </div>
1478 $$
1479 WHERE id = 26 AND template = -- only replace template if it matches stock
1480 $$
1481 [%- USE date -%]
1482 <div>
1483     <style> li { padding: 8px; margin 5px; }</style>
1484     <div>[% date.format %]</div>
1485     <br/>
1486
1487     [% user.family_name %], [% user.first_given_name %]
1488     <ol>
1489     [% FOR circ IN target %]
1490         <li>
1491             <div>[% helpers.get_copy_bib_basics(circ.target_copy.id).title %]</div>
1492             <div>Barcode: [% circ.target_copy.barcode %]</div>
1493             <div>Checked Out: [% date.format(helpers.format_date(circ.xact_start), '%Y-%m-%d') %]</div>
1494             <div>Due Date: [% date.format(helpers.format_date(circ.due_date), '%Y-%m-%d') %]</div>
1495             <div>Returned: [% date.format(helpers.format_date(circ.checkin_time), '%Y-%m-%d') %]</div>
1496         </li>
1497     [% END %]
1498     </ol>
1499 </div>
1500 $$;
1501
1502 -- NOTE: ^-- stock CSV template does not include checkin_time, so 
1503 -- no modifications are required.
1504
1505 -- Create circ history rows for existing circ history data.
1506 DO $FUNK$
1507 DECLARE
1508     cur_usr   INTEGER;
1509     cur_circ  action.circulation%ROWTYPE;
1510     last_circ action.circulation%ROWTYPE;
1511     counter   INTEGER DEFAULT 1;
1512 BEGIN
1513
1514     RAISE NOTICE 
1515         'Migrating circ history for % users.  This might take a while...',
1516         (SELECT COUNT(DISTINCT(au.id)) FROM actor.usr au
1517             JOIN actor.usr_setting aus ON (aus.usr = au.id)
1518             WHERE NOT au.deleted AND 
1519                 aus.name ~ '^history.circ.retention_');
1520
1521     FOR cur_usr IN 
1522         SELECT DISTINCT(au.id)
1523             FROM actor.usr au 
1524             JOIN actor.usr_setting aus ON (aus.usr = au.id)
1525             WHERE NOT au.deleted AND 
1526                 aus.name ~ '^history.circ.retention_' LOOP
1527
1528         FOR cur_circ IN SELECT * FROM action.usr_visible_circs(cur_usr) LOOP
1529
1530             PERFORM TRUE FROM asset.copy WHERE id = cur_circ.target_copy;
1531
1532             -- Avoid inserting a circ history row when the circulated
1533             -- item has been (forcibly) removed from the database.
1534             IF NOT FOUND THEN
1535                 CONTINUE;
1536             END IF;
1537
1538             -- Find the last circ in the circ chain.
1539             SELECT INTO last_circ * 
1540                 FROM action.circ_chain(cur_circ.id) 
1541                 ORDER BY xact_start DESC LIMIT 1;
1542
1543             -- Create the history row.
1544             -- It's OK if last_circ = cur_circ
1545             INSERT INTO action.usr_circ_history 
1546                 (usr, xact_start, target_copy, 
1547                     due_date, checkin_time, source_circ)
1548             VALUES (
1549                 cur_circ.usr, 
1550                 cur_circ.xact_start, 
1551                 cur_circ.target_copy, 
1552                 last_circ.due_date, 
1553                 last_circ.checkin_time,
1554                 cur_circ.id
1555             );
1556
1557             -- useful for alleviating administrator anxiety.
1558             IF counter % 10000 = 0 THEN
1559                 RAISE NOTICE 'Migrated history for % total circs', counter;
1560             END IF;
1561
1562             counter := counter + 1;
1563
1564         END LOOP;
1565     END LOOP;
1566
1567 END $FUNK$;
1568
1569 DROP FUNCTION IF EXISTS action.usr_visible_circs (INTEGER);
1570 DROP FUNCTION IF EXISTS action.usr_visible_circ_copies (INTEGER);
1571
1572 -- remove user retention age checks
1573 CREATE OR REPLACE FUNCTION action.purge_circulations () RETURNS INT AS $func$
1574 DECLARE
1575     org_keep_age    INTERVAL;
1576     org_use_last    BOOL = false;
1577     org_age_is_min  BOOL = false;
1578     org_keep_count  INT;
1579
1580     keep_age        INTERVAL;
1581
1582     target_acp      RECORD;
1583     circ_chain_head action.circulation%ROWTYPE;
1584     circ_chain_tail action.circulation%ROWTYPE;
1585
1586     count_purged    INT;
1587     num_incomplete  INT;
1588
1589     last_finished   TIMESTAMP WITH TIME ZONE;
1590 BEGIN
1591
1592     count_purged := 0;
1593
1594     SELECT value::INTERVAL INTO org_keep_age FROM config.global_flag WHERE name = 'history.circ.retention_age' AND enabled;
1595
1596     SELECT value::INT INTO org_keep_count FROM config.global_flag WHERE name = 'history.circ.retention_count' AND enabled;
1597     IF org_keep_count IS NULL THEN
1598         RETURN count_purged; -- Gimme a count to keep, or I keep them all, forever
1599     END IF;
1600
1601     SELECT enabled INTO org_use_last FROM config.global_flag WHERE name = 'history.circ.retention_uses_last_finished';
1602     SELECT enabled INTO org_age_is_min FROM config.global_flag WHERE name = 'history.circ.retention_age_is_min';
1603
1604     -- First, find copies with more than keep_count non-renewal circs
1605     FOR target_acp IN
1606         SELECT  target_copy,
1607                 COUNT(*) AS total_real_circs
1608           FROM  action.circulation
1609           WHERE parent_circ IS NULL
1610                 AND xact_finish IS NOT NULL
1611           GROUP BY target_copy
1612           HAVING COUNT(*) > org_keep_count
1613     LOOP
1614         -- And, for those, select circs that are finished and older than keep_age
1615         FOR circ_chain_head IN
1616             -- For reference, the subquery uses a window function to order the circs newest to oldest and number them
1617             -- The outer query then uses that information to skip the most recent set the library wants to keep
1618             -- End result is we don't care what order they come out in, as they are all potentials for deletion.
1619             SELECT ac.* FROM action.circulation ac JOIN (
1620               SELECT  rank() OVER (ORDER BY xact_start DESC), ac.id
1621                 FROM  action.circulation ac
1622                 WHERE ac.target_copy = target_acp.target_copy
1623                   AND ac.parent_circ IS NULL
1624                 ORDER BY ac.xact_start ) ranked USING (id)
1625                 WHERE ranked.rank > org_keep_count
1626         LOOP
1627
1628             SELECT * INTO circ_chain_tail FROM action.circ_chain(circ_chain_head.id) ORDER BY xact_start DESC LIMIT 1;
1629             SELECT COUNT(CASE WHEN xact_finish IS NULL THEN 1 ELSE NULL END), MAX(xact_finish) INTO num_incomplete, last_finished FROM action.circ_chain(circ_chain_head.id);
1630             CONTINUE WHEN circ_chain_tail.xact_finish IS NULL OR num_incomplete > 0;
1631
1632             IF NOT org_use_last THEN
1633                 last_finished := circ_chain_tail.xact_finish;
1634             END IF;
1635
1636             keep_age := COALESCE( org_keep_age, '2000 years'::INTERVAL );
1637
1638             IF org_age_is_min THEN
1639                 keep_age := GREATEST( keep_age, org_keep_age );
1640             END IF;
1641
1642             CONTINUE WHEN AGE(NOW(), last_finished) < keep_age;
1643
1644             -- We've passed the purging tests, purge the circ chain starting at the end
1645             -- A trigger should auto-purge the rest of the chain.
1646             DELETE FROM action.circulation WHERE id = circ_chain_tail.id;
1647
1648             count_purged := count_purged + 1;
1649
1650         END LOOP;
1651     END LOOP;
1652
1653     return count_purged;
1654 END;
1655 $func$ LANGUAGE PLPGSQL;
1656
1657 -- delete circ history rows when a user is purged.
1658 CREATE OR REPLACE FUNCTION actor.usr_purge_data(
1659         src_usr  IN INTEGER,
1660         specified_dest_usr IN INTEGER
1661 ) RETURNS VOID AS $$
1662 DECLARE
1663         suffix TEXT;
1664         renamable_row RECORD;
1665         dest_usr INTEGER;
1666 BEGIN
1667
1668         IF specified_dest_usr IS NULL THEN
1669                 dest_usr := 1; -- Admin user on stock installs
1670         ELSE
1671                 dest_usr := specified_dest_usr;
1672         END IF;
1673
1674         -- acq.*
1675         UPDATE acq.fund_allocation SET allocator = dest_usr WHERE allocator = src_usr;
1676         UPDATE acq.lineitem SET creator = dest_usr WHERE creator = src_usr;
1677         UPDATE acq.lineitem SET editor = dest_usr WHERE editor = src_usr;
1678         UPDATE acq.lineitem SET selector = dest_usr WHERE selector = src_usr;
1679         UPDATE acq.lineitem_note SET creator = dest_usr WHERE creator = src_usr;
1680         UPDATE acq.lineitem_note SET editor = dest_usr WHERE editor = src_usr;
1681         DELETE FROM acq.lineitem_usr_attr_definition WHERE usr = src_usr;
1682
1683         -- Update with a rename to avoid collisions
1684         FOR renamable_row in
1685                 SELECT id, name
1686                 FROM   acq.picklist
1687                 WHERE  owner = src_usr
1688         LOOP
1689                 suffix := ' (' || src_usr || ')';
1690                 LOOP
1691                         BEGIN
1692                                 UPDATE  acq.picklist
1693                                 SET     owner = dest_usr, name = name || suffix
1694                                 WHERE   id = renamable_row.id;
1695                         EXCEPTION WHEN unique_violation THEN
1696                                 suffix := suffix || ' ';
1697                                 CONTINUE;
1698                         END;
1699                         EXIT;
1700                 END LOOP;
1701         END LOOP;
1702
1703         UPDATE acq.picklist SET creator = dest_usr WHERE creator = src_usr;
1704         UPDATE acq.picklist SET editor = dest_usr WHERE editor = src_usr;
1705         UPDATE acq.po_note SET creator = dest_usr WHERE creator = src_usr;
1706         UPDATE acq.po_note SET editor = dest_usr WHERE editor = src_usr;
1707         UPDATE acq.purchase_order SET owner = dest_usr WHERE owner = src_usr;
1708         UPDATE acq.purchase_order SET creator = dest_usr WHERE creator = src_usr;
1709         UPDATE acq.purchase_order SET editor = dest_usr WHERE editor = src_usr;
1710         UPDATE acq.claim_event SET creator = dest_usr WHERE creator = src_usr;
1711
1712         -- action.*
1713         DELETE FROM action.circulation WHERE usr = src_usr;
1714         UPDATE action.circulation SET circ_staff = dest_usr WHERE circ_staff = src_usr;
1715         UPDATE action.circulation SET checkin_staff = dest_usr WHERE checkin_staff = src_usr;
1716         UPDATE action.hold_notification SET notify_staff = dest_usr WHERE notify_staff = src_usr;
1717         UPDATE action.hold_request SET fulfillment_staff = dest_usr WHERE fulfillment_staff = src_usr;
1718         UPDATE action.hold_request SET requestor = dest_usr WHERE requestor = src_usr;
1719         DELETE FROM action.hold_request WHERE usr = src_usr;
1720         UPDATE action.in_house_use SET staff = dest_usr WHERE staff = src_usr;
1721         UPDATE action.non_cat_in_house_use SET staff = dest_usr WHERE staff = src_usr;
1722         DELETE FROM action.non_cataloged_circulation WHERE patron = src_usr;
1723         UPDATE action.non_cataloged_circulation SET staff = dest_usr WHERE staff = src_usr;
1724         DELETE FROM action.survey_response WHERE usr = src_usr;
1725         UPDATE action.fieldset SET owner = dest_usr WHERE owner = src_usr;
1726     DELETE FROM action.usr_circ_history WHERE usr = src_usr;
1727
1728         -- actor.*
1729         DELETE FROM actor.card WHERE usr = src_usr;
1730         DELETE FROM actor.stat_cat_entry_usr_map WHERE target_usr = src_usr;
1731
1732         -- The following update is intended to avoid transient violations of a foreign
1733         -- key constraint, whereby actor.usr_address references itself.  It may not be
1734         -- necessary, but it does no harm.
1735         UPDATE actor.usr_address SET replaces = NULL
1736                 WHERE usr = src_usr AND replaces IS NOT NULL;
1737         DELETE FROM actor.usr_address WHERE usr = src_usr;
1738         DELETE FROM actor.usr_note WHERE usr = src_usr;
1739         UPDATE actor.usr_note SET creator = dest_usr WHERE creator = src_usr;
1740         DELETE FROM actor.usr_org_unit_opt_in WHERE usr = src_usr;
1741         UPDATE actor.usr_org_unit_opt_in SET staff = dest_usr WHERE staff = src_usr;
1742         DELETE FROM actor.usr_setting WHERE usr = src_usr;
1743         DELETE FROM actor.usr_standing_penalty WHERE usr = src_usr;
1744         UPDATE actor.usr_standing_penalty SET staff = dest_usr WHERE staff = src_usr;
1745
1746         -- asset.*
1747         UPDATE asset.call_number SET creator = dest_usr WHERE creator = src_usr;
1748         UPDATE asset.call_number SET editor = dest_usr WHERE editor = src_usr;
1749         UPDATE asset.call_number_note SET creator = dest_usr WHERE creator = src_usr;
1750         UPDATE asset.copy SET creator = dest_usr WHERE creator = src_usr;
1751         UPDATE asset.copy SET editor = dest_usr WHERE editor = src_usr;
1752         UPDATE asset.copy_note SET creator = dest_usr WHERE creator = src_usr;
1753
1754         -- auditor.*
1755         DELETE FROM auditor.actor_usr_address_history WHERE id = src_usr;
1756         DELETE FROM auditor.actor_usr_history WHERE id = src_usr;
1757         UPDATE auditor.asset_call_number_history SET creator = dest_usr WHERE creator = src_usr;
1758         UPDATE auditor.asset_call_number_history SET editor  = dest_usr WHERE editor  = src_usr;
1759         UPDATE auditor.asset_copy_history SET creator = dest_usr WHERE creator = src_usr;
1760         UPDATE auditor.asset_copy_history SET editor  = dest_usr WHERE editor  = src_usr;
1761         UPDATE auditor.biblio_record_entry_history SET creator = dest_usr WHERE creator = src_usr;
1762         UPDATE auditor.biblio_record_entry_history SET editor  = dest_usr WHERE editor  = src_usr;
1763
1764         -- biblio.*
1765         UPDATE biblio.record_entry SET creator = dest_usr WHERE creator = src_usr;
1766         UPDATE biblio.record_entry SET editor = dest_usr WHERE editor = src_usr;
1767         UPDATE biblio.record_note SET creator = dest_usr WHERE creator = src_usr;
1768         UPDATE biblio.record_note SET editor = dest_usr WHERE editor = src_usr;
1769
1770         -- container.*
1771         -- Update buckets with a rename to avoid collisions
1772         FOR renamable_row in
1773                 SELECT id, name
1774                 FROM   container.biblio_record_entry_bucket
1775                 WHERE  owner = src_usr
1776         LOOP
1777                 suffix := ' (' || src_usr || ')';
1778                 LOOP
1779                         BEGIN
1780                                 UPDATE  container.biblio_record_entry_bucket
1781                                 SET     owner = dest_usr, name = name || suffix
1782                                 WHERE   id = renamable_row.id;
1783                         EXCEPTION WHEN unique_violation THEN
1784                                 suffix := suffix || ' ';
1785                                 CONTINUE;
1786                         END;
1787                         EXIT;
1788                 END LOOP;
1789         END LOOP;
1790
1791         FOR renamable_row in
1792                 SELECT id, name
1793                 FROM   container.call_number_bucket
1794                 WHERE  owner = src_usr
1795         LOOP
1796                 suffix := ' (' || src_usr || ')';
1797                 LOOP
1798                         BEGIN
1799                                 UPDATE  container.call_number_bucket
1800                                 SET     owner = dest_usr, name = name || suffix
1801                                 WHERE   id = renamable_row.id;
1802                         EXCEPTION WHEN unique_violation THEN
1803                                 suffix := suffix || ' ';
1804                                 CONTINUE;
1805                         END;
1806                         EXIT;
1807                 END LOOP;
1808         END LOOP;
1809
1810         FOR renamable_row in
1811                 SELECT id, name
1812                 FROM   container.copy_bucket
1813                 WHERE  owner = src_usr
1814         LOOP
1815                 suffix := ' (' || src_usr || ')';
1816                 LOOP
1817                         BEGIN
1818                                 UPDATE  container.copy_bucket
1819                                 SET     owner = dest_usr, name = name || suffix
1820                                 WHERE   id = renamable_row.id;
1821                         EXCEPTION WHEN unique_violation THEN
1822                                 suffix := suffix || ' ';
1823                                 CONTINUE;
1824                         END;
1825                         EXIT;
1826                 END LOOP;
1827         END LOOP;
1828
1829         FOR renamable_row in
1830                 SELECT id, name
1831                 FROM   container.user_bucket
1832                 WHERE  owner = src_usr
1833         LOOP
1834                 suffix := ' (' || src_usr || ')';
1835                 LOOP
1836                         BEGIN
1837                                 UPDATE  container.user_bucket
1838                                 SET     owner = dest_usr, name = name || suffix
1839                                 WHERE   id = renamable_row.id;
1840                         EXCEPTION WHEN unique_violation THEN
1841                                 suffix := suffix || ' ';
1842                                 CONTINUE;
1843                         END;
1844                         EXIT;
1845                 END LOOP;
1846         END LOOP;
1847
1848         DELETE FROM container.user_bucket_item WHERE target_user = src_usr;
1849
1850         -- money.*
1851         DELETE FROM money.billable_xact WHERE usr = src_usr;
1852         DELETE FROM money.collections_tracker WHERE usr = src_usr;
1853         UPDATE money.collections_tracker SET collector = dest_usr WHERE collector = src_usr;
1854
1855         -- permission.*
1856         DELETE FROM permission.usr_grp_map WHERE usr = src_usr;
1857         DELETE FROM permission.usr_object_perm_map WHERE usr = src_usr;
1858         DELETE FROM permission.usr_perm_map WHERE usr = src_usr;
1859         DELETE FROM permission.usr_work_ou_map WHERE usr = src_usr;
1860
1861         -- reporter.*
1862         -- Update with a rename to avoid collisions
1863         BEGIN
1864                 FOR renamable_row in
1865                         SELECT id, name
1866                         FROM   reporter.output_folder
1867                         WHERE  owner = src_usr
1868                 LOOP
1869                         suffix := ' (' || src_usr || ')';
1870                         LOOP
1871                                 BEGIN
1872                                         UPDATE  reporter.output_folder
1873                                         SET     owner = dest_usr, name = name || suffix
1874                                         WHERE   id = renamable_row.id;
1875                                 EXCEPTION WHEN unique_violation THEN
1876                                         suffix := suffix || ' ';
1877                                         CONTINUE;
1878                                 END;
1879                                 EXIT;
1880                         END LOOP;
1881                 END LOOP;
1882         EXCEPTION WHEN undefined_table THEN
1883                 -- do nothing
1884         END;
1885
1886         BEGIN
1887                 UPDATE reporter.report SET owner = dest_usr WHERE owner = src_usr;
1888         EXCEPTION WHEN undefined_table THEN
1889                 -- do nothing
1890         END;
1891
1892         -- Update with a rename to avoid collisions
1893         BEGIN
1894                 FOR renamable_row in
1895                         SELECT id, name
1896                         FROM   reporter.report_folder
1897                         WHERE  owner = src_usr
1898                 LOOP
1899                         suffix := ' (' || src_usr || ')';
1900                         LOOP
1901                                 BEGIN
1902                                         UPDATE  reporter.report_folder
1903                                         SET     owner = dest_usr, name = name || suffix
1904                                         WHERE   id = renamable_row.id;
1905                                 EXCEPTION WHEN unique_violation THEN
1906                                         suffix := suffix || ' ';
1907                                         CONTINUE;
1908                                 END;
1909                                 EXIT;
1910                         END LOOP;
1911                 END LOOP;
1912         EXCEPTION WHEN undefined_table THEN
1913                 -- do nothing
1914         END;
1915
1916         BEGIN
1917                 UPDATE reporter.schedule SET runner = dest_usr WHERE runner = src_usr;
1918         EXCEPTION WHEN undefined_table THEN
1919                 -- do nothing
1920         END;
1921
1922         BEGIN
1923                 UPDATE reporter.template SET owner = dest_usr WHERE owner = src_usr;
1924         EXCEPTION WHEN undefined_table THEN
1925                 -- do nothing
1926         END;
1927
1928         -- Update with a rename to avoid collisions
1929         BEGIN
1930                 FOR renamable_row in
1931                         SELECT id, name
1932                         FROM   reporter.template_folder
1933                         WHERE  owner = src_usr
1934                 LOOP
1935                         suffix := ' (' || src_usr || ')';
1936                         LOOP
1937                                 BEGIN
1938                                         UPDATE  reporter.template_folder
1939                                         SET     owner = dest_usr, name = name || suffix
1940                                         WHERE   id = renamable_row.id;
1941                                 EXCEPTION WHEN unique_violation THEN
1942                                         suffix := suffix || ' ';
1943                                         CONTINUE;
1944                                 END;
1945                                 EXIT;
1946                         END LOOP;
1947                 END LOOP;
1948         EXCEPTION WHEN undefined_table THEN
1949         -- do nothing
1950         END;
1951
1952         -- vandelay.*
1953         -- Update with a rename to avoid collisions
1954         FOR renamable_row in
1955                 SELECT id, name
1956                 FROM   vandelay.queue
1957                 WHERE  owner = src_usr
1958         LOOP
1959                 suffix := ' (' || src_usr || ')';
1960                 LOOP
1961                         BEGIN
1962                                 UPDATE  vandelay.queue
1963                                 SET     owner = dest_usr, name = name || suffix
1964                                 WHERE   id = renamable_row.id;
1965                         EXCEPTION WHEN unique_violation THEN
1966                                 suffix := suffix || ' ';
1967                                 CONTINUE;
1968                         END;
1969                         EXIT;
1970                 END LOOP;
1971         END LOOP;
1972
1973     -- NULL-ify addresses last so other cleanup (e.g. circ anonymization)
1974     -- can access the information before deletion.
1975         UPDATE actor.usr SET
1976                 active = FALSE,
1977                 card = NULL,
1978                 mailing_address = NULL,
1979                 billing_address = NULL
1980         WHERE id = src_usr;
1981
1982 END;
1983 $$ LANGUAGE plpgsql;
1984
1985 SELECT evergreen.upgrade_deps_block_check('0961', :eg_version);
1986
1987 CREATE EXTENSION IF NOT EXISTS pgcrypto;
1988
1989 CREATE TABLE actor.passwd_type (
1990     code        TEXT PRIMARY KEY,
1991     name        TEXT UNIQUE NOT NULL,
1992     login       BOOLEAN NOT NULL DEFAULT FALSE,
1993     regex       TEXT,   -- pending
1994     crypt_algo  TEXT,   -- e.g. 'bf'
1995
1996     -- gen_salt() iter count used with each new salt.
1997     -- A non-NULL value for iter_count is our indication the 
1998     -- password is salted and encrypted via crypt()
1999     iter_count  INTEGER CHECK (iter_count IS NULL OR iter_count > 0)
2000 );
2001
2002 CREATE TABLE actor.passwd (
2003     id          SERIAL PRIMARY KEY,
2004     usr         INTEGER NOT NULL REFERENCES actor.usr(id)
2005                 ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
2006     salt        TEXT, -- will be NULL for non-crypt'ed passwords
2007     passwd      TEXT NOT NULL,
2008     passwd_type TEXT NOT NULL REFERENCES actor.passwd_type(code)
2009                 DEFERRABLE INITIALLY DEFERRED,
2010     create_date TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
2011     edit_date   TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
2012     CONSTRAINT  passwd_type_once_per_user UNIQUE (usr, passwd_type)
2013 );
2014
2015 CREATE OR REPLACE FUNCTION actor.create_salt(pw_type TEXT)
2016     RETURNS TEXT AS $$
2017 DECLARE
2018     type_row actor.passwd_type%ROWTYPE;
2019 BEGIN
2020     /* Returns a new salt based on the passwd_type encryption settings.
2021      * Returns NULL If the password type is not crypt()'ed.
2022      */
2023
2024     SELECT INTO type_row * FROM actor.passwd_type WHERE code = pw_type;
2025
2026     IF NOT FOUND THEN
2027         RETURN EXCEPTION 'No such password type: %', pw_type;
2028     END IF;
2029
2030     IF type_row.iter_count IS NULL THEN
2031         -- This password type is unsalted.  That's OK.
2032         RETURN NULL;
2033     END IF;
2034
2035     RETURN gen_salt(type_row.crypt_algo, type_row.iter_count);
2036 END;
2037 $$ LANGUAGE PLPGSQL;
2038
2039
2040 /* 
2041     TODO: when a user changes their password in the application, the
2042     app layer has access to the bare password.  At that point, we have
2043     the opportunity to store the new password without the MD5(MD5())
2044     intermediate hashing.  Do we care?  We would need a way to indicate
2045     which passwords have the legacy intermediate hashing and which don't
2046     so the app layer would know whether it should perform the intermediate
2047     hashing.  In either event, with the exception of migrate_passwd(), the
2048     DB functions know or care nothing about intermediate hashing.  Every
2049     password is just a value that may or may not be internally crypt'ed. 
2050 */
2051
2052 CREATE OR REPLACE FUNCTION actor.set_passwd(
2053     pw_usr INTEGER, pw_type TEXT, new_pass TEXT, new_salt TEXT DEFAULT NULL)
2054     RETURNS BOOLEAN AS $$
2055 DECLARE
2056     pw_salt TEXT;
2057     pw_text TEXT;
2058 BEGIN
2059     /* Sets the password value, creating a new actor.passwd row if needed.
2060      * If the password type supports it, the new_pass value is crypt()'ed.
2061      * For crypt'ed passwords, the salt comes from one of 3 places in order:
2062      * new_salt (if present), existing salt (if present), newly created 
2063      * salt.
2064      */
2065
2066     IF new_salt IS NOT NULL THEN
2067         pw_salt := new_salt;
2068     ELSE 
2069         pw_salt := actor.get_salt(pw_usr, pw_type);
2070
2071         IF pw_salt IS NULL THEN
2072             /* We have no salt for this user + type.  Assume they want a 
2073              * new salt.  If this type is unsalted, create_salt() will 
2074              * return NULL. */
2075             pw_salt := actor.create_salt(pw_type);
2076         END IF;
2077     END IF;
2078
2079     IF pw_salt IS NULL THEN 
2080         pw_text := new_pass; -- unsalted, use as-is.
2081     ELSE
2082         pw_text := CRYPT(new_pass, pw_salt);
2083     END IF;
2084
2085     UPDATE actor.passwd 
2086         SET passwd = pw_text, salt = pw_salt, edit_date = NOW()
2087         WHERE usr = pw_usr AND passwd_type = pw_type;
2088
2089     IF NOT FOUND THEN
2090         -- no password row exists for this user + type.  Create one.
2091         INSERT INTO actor.passwd (usr, passwd_type, salt, passwd) 
2092             VALUES (pw_usr, pw_type, pw_salt, pw_text);
2093     END IF;
2094
2095     RETURN TRUE;
2096 END;
2097 $$ LANGUAGE PLPGSQL;
2098
2099 CREATE OR REPLACE FUNCTION actor.get_salt(pw_usr INTEGER, pw_type TEXT)
2100     RETURNS TEXT AS $$
2101 DECLARE
2102     pw_salt TEXT;
2103     type_row actor.passwd_type%ROWTYPE;
2104 BEGIN
2105     /* Returns the salt for the requested user + type.  If the password 
2106      * type of "main" is requested and no password exists in actor.passwd, 
2107      * the user's existing password is migrated and the new salt is returned.
2108      * Returns NULL if the password type is not crypt'ed (iter_count is NULL).
2109      */
2110
2111     SELECT INTO pw_salt salt FROM actor.passwd 
2112         WHERE usr = pw_usr AND passwd_type = pw_type;
2113
2114     IF FOUND THEN
2115         RETURN pw_salt;
2116     END IF;
2117
2118     IF pw_type = 'main' THEN
2119         -- Main password has not yet been migrated. 
2120         -- Do it now and return the newly created salt.
2121         RETURN actor.migrate_passwd(pw_usr);
2122     END IF;
2123
2124     -- We have no salt to return.  actor.create_salt() needed.
2125     RETURN NULL;
2126 END;
2127 $$ LANGUAGE PLPGSQL;
2128
2129 CREATE OR REPLACE FUNCTION 
2130     actor.migrate_passwd(pw_usr INTEGER) RETURNS TEXT AS $$
2131 DECLARE
2132     pw_salt TEXT;
2133     usr_row actor.usr%ROWTYPE;
2134 BEGIN
2135     /* Migrates legacy actor.usr.passwd value to actor.passwd with 
2136      * a password type 'main' and returns the new salt.  For backwards
2137      * compatibility with existing CHAP-style API's, we perform a 
2138      * layer of intermediate MD5(MD5()) hashing.  This is intermediate
2139      * hashing is not required of other passwords.
2140      */
2141
2142     -- Avoid calling get_salt() here, because it may result in a 
2143     -- migrate_passwd() call, creating a loop.
2144     SELECT INTO pw_salt salt FROM actor.passwd 
2145         WHERE usr = pw_usr AND passwd_type = 'main';
2146
2147     -- Only migrate passwords that have not already been migrated.
2148     IF FOUND THEN
2149         RETURN pw_salt;
2150     END IF;
2151
2152     SELECT INTO usr_row * FROM actor.usr WHERE id = pw_usr;
2153
2154     pw_salt := actor.create_salt('main');
2155
2156     PERFORM actor.set_passwd(
2157         pw_usr, 'main', MD5(pw_salt || usr_row.passwd), pw_salt);
2158
2159     -- clear the existing password
2160     UPDATE actor.usr SET passwd = '' WHERE id = usr_row.id;
2161
2162     RETURN pw_salt;
2163 END;
2164 $$ LANGUAGE PLPGSQL;
2165
2166 CREATE OR REPLACE FUNCTION 
2167     actor.verify_passwd(pw_usr INTEGER, pw_type TEXT, test_passwd TEXT) 
2168     RETURNS BOOLEAN AS $$
2169 DECLARE
2170     pw_salt TEXT;
2171 BEGIN
2172     /* Returns TRUE if the password provided matches the in-db password.  
2173      * If the password type is salted, we compare the output of CRYPT().
2174      * NOTE: test_passwd is MD5(salt || MD5(password)) for legacy 
2175      * 'main' passwords.
2176      */
2177
2178     SELECT INTO pw_salt salt FROM actor.passwd 
2179         WHERE usr = pw_usr AND passwd_type = pw_type;
2180
2181     IF NOT FOUND THEN
2182         -- no such password
2183         RETURN FALSE;
2184     END IF;
2185
2186     IF pw_salt IS NULL THEN
2187         -- Password is unsalted, compare the un-CRYPT'ed values.
2188         RETURN EXISTS (
2189             SELECT TRUE FROM actor.passwd WHERE 
2190                 usr = pw_usr AND
2191                 passwd_type = pw_type AND
2192                 passwd = test_passwd
2193         );
2194     END IF;
2195
2196     RETURN EXISTS (
2197         SELECT TRUE FROM actor.passwd WHERE 
2198             usr = pw_usr AND
2199             passwd_type = pw_type AND
2200             passwd = CRYPT(test_passwd, pw_salt)
2201     );
2202 END;
2203 $$ STRICT LANGUAGE PLPGSQL;
2204
2205 --- DATA ----------------------
2206
2207 INSERT INTO actor.passwd_type 
2208     (code, name, login, crypt_algo, iter_count) 
2209     VALUES ('main', 'Main Login Password', TRUE, 'bf', 10);
2210
2211 SELECT evergreen.upgrade_deps_block_check('0962', :eg_version);
2212
2213 ALTER TABLE vandelay.import_item_attr_definition
2214     ADD COLUMN parts_data TEXT;
2215
2216 ALTER TABLE vandelay.import_item
2217     ADD COLUMN parts_data TEXT;
2218
2219 CREATE OR REPLACE FUNCTION vandelay.ingest_items ( import_id BIGINT, attr_def_id BIGINT ) RETURNS SETOF vandelay.import_item AS $$
2220 DECLARE
2221
2222     owning_lib      TEXT;
2223     circ_lib        TEXT;
2224     call_number     TEXT;
2225     copy_number     TEXT;
2226     status          TEXT;
2227     location        TEXT;
2228     circulate       TEXT;
2229     deposit         TEXT;
2230     deposit_amount  TEXT;
2231     ref             TEXT;
2232     holdable        TEXT;
2233     price           TEXT;
2234     barcode         TEXT;
2235     circ_modifier   TEXT;
2236     circ_as_type    TEXT;
2237     alert_message   TEXT;
2238     opac_visible    TEXT;
2239     pub_note        TEXT;
2240     priv_note       TEXT;
2241     internal_id     TEXT;
2242     stat_cat_data   TEXT;
2243     parts_data      TEXT;
2244
2245     attr_def        RECORD;
2246     tmp_attr_set    RECORD;
2247     attr_set        vandelay.import_item%ROWTYPE;
2248
2249     xpaths          TEXT[];
2250     tmp_str         TEXT;
2251
2252 BEGIN
2253
2254     SELECT * INTO attr_def FROM vandelay.import_item_attr_definition WHERE id = attr_def_id;
2255
2256     IF FOUND THEN
2257
2258         attr_set.definition := attr_def.id;
2259
2260         -- Build the combined XPath
2261
2262         owning_lib :=
2263             CASE
2264                 WHEN attr_def.owning_lib IS NULL THEN 'null()'
2265                 WHEN LENGTH( attr_def.owning_lib ) = 1 THEN '*[@code="' || attr_def.owning_lib || '"]'
2266                 ELSE '*' || attr_def.owning_lib
2267             END;
2268
2269         circ_lib :=
2270             CASE
2271                 WHEN attr_def.circ_lib IS NULL THEN 'null()'
2272                 WHEN LENGTH( attr_def.circ_lib ) = 1 THEN '*[@code="' || attr_def.circ_lib || '"]'
2273                 ELSE '*' || attr_def.circ_lib
2274             END;
2275
2276         call_number :=
2277             CASE
2278                 WHEN attr_def.call_number IS NULL THEN 'null()'
2279                 WHEN LENGTH( attr_def.call_number ) = 1 THEN '*[@code="' || attr_def.call_number || '"]'
2280                 ELSE '*' || attr_def.call_number
2281             END;
2282
2283         copy_number :=
2284             CASE
2285                 WHEN attr_def.copy_number IS NULL THEN 'null()'
2286                 WHEN LENGTH( attr_def.copy_number ) = 1 THEN '*[@code="' || attr_def.copy_number || '"]'
2287                 ELSE '*' || attr_def.copy_number
2288             END;
2289
2290         status :=
2291             CASE
2292                 WHEN attr_def.status IS NULL THEN 'null()'
2293                 WHEN LENGTH( attr_def.status ) = 1 THEN '*[@code="' || attr_def.status || '"]'
2294                 ELSE '*' || attr_def.status
2295             END;
2296
2297         location :=
2298             CASE
2299                 WHEN attr_def.location IS NULL THEN 'null()'
2300                 WHEN LENGTH( attr_def.location ) = 1 THEN '*[@code="' || attr_def.location || '"]'
2301                 ELSE '*' || attr_def.location
2302             END;
2303
2304         circulate :=
2305             CASE
2306                 WHEN attr_def.circulate IS NULL THEN 'null()'
2307                 WHEN LENGTH( attr_def.circulate ) = 1 THEN '*[@code="' || attr_def.circulate || '"]'
2308                 ELSE '*' || attr_def.circulate
2309             END;
2310
2311         deposit :=
2312             CASE
2313                 WHEN attr_def.deposit IS NULL THEN 'null()'
2314                 WHEN LENGTH( attr_def.deposit ) = 1 THEN '*[@code="' || attr_def.deposit || '"]'
2315                 ELSE '*' || attr_def.deposit
2316             END;
2317
2318         deposit_amount :=
2319             CASE
2320                 WHEN attr_def.deposit_amount IS NULL THEN 'null()'
2321                 WHEN LENGTH( attr_def.deposit_amount ) = 1 THEN '*[@code="' || attr_def.deposit_amount || '"]'
2322                 ELSE '*' || attr_def.deposit_amount
2323             END;
2324
2325         ref :=
2326             CASE
2327                 WHEN attr_def.ref IS NULL THEN 'null()'
2328                 WHEN LENGTH( attr_def.ref ) = 1 THEN '*[@code="' || attr_def.ref || '"]'
2329                 ELSE '*' || attr_def.ref
2330             END;
2331
2332         holdable :=
2333             CASE
2334                 WHEN attr_def.holdable IS NULL THEN 'null()'
2335                 WHEN LENGTH( attr_def.holdable ) = 1 THEN '*[@code="' || attr_def.holdable || '"]'
2336                 ELSE '*' || attr_def.holdable
2337             END;
2338
2339         price :=
2340             CASE
2341                 WHEN attr_def.price IS NULL THEN 'null()'
2342                 WHEN LENGTH( attr_def.price ) = 1 THEN '*[@code="' || attr_def.price || '"]'
2343                 ELSE '*' || attr_def.price
2344             END;
2345
2346         barcode :=
2347             CASE
2348                 WHEN attr_def.barcode IS NULL THEN 'null()'
2349                 WHEN LENGTH( attr_def.barcode ) = 1 THEN '*[@code="' || attr_def.barcode || '"]'
2350                 ELSE '*' || attr_def.barcode
2351             END;
2352
2353         circ_modifier :=
2354             CASE
2355                 WHEN attr_def.circ_modifier IS NULL THEN 'null()'
2356                 WHEN LENGTH( attr_def.circ_modifier ) = 1 THEN '*[@code="' || attr_def.circ_modifier || '"]'
2357                 ELSE '*' || attr_def.circ_modifier
2358             END;
2359
2360         circ_as_type :=
2361             CASE
2362                 WHEN attr_def.circ_as_type IS NULL THEN 'null()'
2363                 WHEN LENGTH( attr_def.circ_as_type ) = 1 THEN '*[@code="' || attr_def.circ_as_type || '"]'
2364                 ELSE '*' || attr_def.circ_as_type
2365             END;
2366
2367         alert_message :=
2368             CASE
2369                 WHEN attr_def.alert_message IS NULL THEN 'null()'
2370                 WHEN LENGTH( attr_def.alert_message ) = 1 THEN '*[@code="' || attr_def.alert_message || '"]'
2371                 ELSE '*' || attr_def.alert_message
2372             END;
2373
2374         opac_visible :=
2375             CASE
2376                 WHEN attr_def.opac_visible IS NULL THEN 'null()'
2377                 WHEN LENGTH( attr_def.opac_visible ) = 1 THEN '*[@code="' || attr_def.opac_visible || '"]'
2378                 ELSE '*' || attr_def.opac_visible
2379             END;
2380
2381         pub_note :=
2382             CASE
2383                 WHEN attr_def.pub_note IS NULL THEN 'null()'
2384                 WHEN LENGTH( attr_def.pub_note ) = 1 THEN '*[@code="' || attr_def.pub_note || '"]'
2385                 ELSE '*' || attr_def.pub_note
2386             END;
2387         priv_note :=
2388             CASE
2389                 WHEN attr_def.priv_note IS NULL THEN 'null()'
2390                 WHEN LENGTH( attr_def.priv_note ) = 1 THEN '*[@code="' || attr_def.priv_note || '"]'
2391                 ELSE '*' || attr_def.priv_note
2392             END;
2393
2394         internal_id :=
2395             CASE
2396                 WHEN attr_def.internal_id IS NULL THEN 'null()'
2397                 WHEN LENGTH( attr_def.internal_id ) = 1 THEN '*[@code="' || attr_def.internal_id || '"]'
2398                 ELSE '*' || attr_def.internal_id
2399             END;
2400
2401         stat_cat_data :=
2402             CASE
2403                 WHEN attr_def.stat_cat_data IS NULL THEN 'null()'
2404                 WHEN LENGTH( attr_def.stat_cat_data ) = 1 THEN '*[@code="' || attr_def.stat_cat_data || '"]'
2405                 ELSE '*' || attr_def.stat_cat_data
2406             END;
2407
2408         parts_data :=
2409             CASE
2410                 WHEN attr_def.parts_data IS NULL THEN 'null()'
2411                 WHEN LENGTH( attr_def.parts_data ) = 1 THEN '*[@code="' || attr
2412                 ELSE '*' || attr_def.parts_data
2413             END;
2414
2415
2416
2417         xpaths := ARRAY[owning_lib, circ_lib, call_number, copy_number, status, location, circulate,
2418                         deposit, deposit_amount, ref, holdable, price, barcode, circ_modifier, circ_as_type,
2419                         alert_message, pub_note, priv_note, internal_id, stat_cat_data, parts_data, opac_visible];
2420
2421         FOR tmp_attr_set IN
2422                 SELECT  *
2423                   FROM  oils_xpath_tag_to_table( (SELECT marc FROM vandelay.queued_bib_record WHERE id = import_id), attr_def.tag, xpaths)
2424                             AS t( ol TEXT, clib TEXT, cn TEXT, cnum TEXT, cs TEXT, cl TEXT, circ TEXT,
2425                                   dep TEXT, dep_amount TEXT, r TEXT, hold TEXT, pr TEXT, bc TEXT, circ_mod TEXT,
2426                                   circ_as TEXT, amessage TEXT, note TEXT, pnote TEXT, internal_id TEXT,
2427                                   stat_cat_data TEXT, parts_data TEXT, opac_vis TEXT )
2428         LOOP
2429
2430             attr_set.import_error := NULL;
2431             attr_set.error_detail := NULL;
2432             attr_set.deposit_amount := NULL;
2433             attr_set.copy_number := NULL;
2434             attr_set.price := NULL;
2435             attr_set.circ_modifier := NULL;
2436             attr_set.location := NULL;
2437             attr_set.barcode := NULL;
2438             attr_set.call_number := NULL;
2439
2440             IF tmp_attr_set.pr != '' THEN
2441                 tmp_str = REGEXP_REPLACE(tmp_attr_set.pr, E'[^0-9\\.]', '', 'g');
2442                 IF tmp_str = '' THEN
2443                     attr_set.import_error := 'import.item.invalid.price';
2444                     attr_set.error_detail := tmp_attr_set.pr; -- original value
2445                     RETURN NEXT attr_set; CONTINUE;
2446                 END IF;
2447                 attr_set.price := tmp_str::NUMERIC(8,2);
2448             END IF;
2449
2450             IF tmp_attr_set.dep_amount != '' THEN
2451                 tmp_str = REGEXP_REPLACE(tmp_attr_set.dep_amount, E'[^0-9\\.]', '', 'g');
2452                 IF tmp_str = '' THEN
2453                     attr_set.import_error := 'import.item.invalid.deposit_amount';
2454                     attr_set.error_detail := tmp_attr_set.dep_amount;
2455                     RETURN NEXT attr_set; CONTINUE;
2456                 END IF;
2457                 attr_set.deposit_amount := tmp_str::NUMERIC(8,2);
2458             END IF;
2459
2460             IF tmp_attr_set.cnum != '' THEN
2461                 tmp_str = REGEXP_REPLACE(tmp_attr_set.cnum, E'[^0-9]', '', 'g');
2462                 IF tmp_str = '' THEN
2463                     attr_set.import_error := 'import.item.invalid.copy_number';
2464                     attr_set.error_detail := tmp_attr_set.cnum;
2465                     RETURN NEXT attr_set; CONTINUE;
2466                 END IF;
2467                 attr_set.copy_number := tmp_str::INT;
2468             END IF;
2469
2470             IF tmp_attr_set.ol != '' THEN
2471                 SELECT id INTO attr_set.owning_lib FROM actor.org_unit WHERE shortname = UPPER(tmp_attr_set.ol); -- INT
2472                 IF NOT FOUND THEN
2473                     attr_set.import_error := 'import.item.invalid.owning_lib';
2474                     attr_set.error_detail := tmp_attr_set.ol;
2475                     RETURN NEXT attr_set; CONTINUE;
2476                 END IF;
2477             END IF;
2478
2479             IF tmp_attr_set.clib != '' THEN
2480                 SELECT id INTO attr_set.circ_lib FROM actor.org_unit WHERE shortname = UPPER(tmp_attr_set.clib); -- INT
2481                 IF NOT FOUND THEN
2482                     attr_set.import_error := 'import.item.invalid.circ_lib';
2483                     attr_set.error_detail := tmp_attr_set.clib;
2484                     RETURN NEXT attr_set; CONTINUE;
2485                 END IF;
2486             END IF;
2487
2488             IF tmp_attr_set.cs != '' THEN
2489                 SELECT id INTO attr_set.status FROM config.copy_status WHERE LOWER(name) = LOWER(tmp_attr_set.cs); -- INT
2490                 IF NOT FOUND THEN
2491                     attr_set.import_error := 'import.item.invalid.status';
2492                     attr_set.error_detail := tmp_attr_set.cs;
2493                     RETURN NEXT attr_set; CONTINUE;
2494                 END IF;
2495             END IF;
2496
2497             IF COALESCE(tmp_attr_set.circ_mod, '') = '' THEN
2498
2499                 -- no circ mod defined, see if we should apply a default
2500                 SELECT INTO attr_set.circ_modifier TRIM(BOTH '"' FROM value)
2501                     FROM actor.org_unit_ancestor_setting(
2502                         'vandelay.item.circ_modifier.default',
2503                         attr_set.owning_lib
2504                     );
2505
2506                 -- make sure the value from the org setting is still valid
2507                 PERFORM 1 FROM config.circ_modifier WHERE code = attr_set.circ_modifier;
2508                 IF NOT FOUND THEN
2509                     attr_set.import_error := 'import.item.invalid.circ_modifier';
2510                     attr_set.error_detail := tmp_attr_set.circ_mod;
2511                     RETURN NEXT attr_set; CONTINUE;
2512                 END IF;
2513
2514             ELSE
2515
2516                 SELECT code INTO attr_set.circ_modifier FROM config.circ_modifier WHERE code = tmp_attr_set.circ_mod;
2517                 IF NOT FOUND THEN
2518                     attr_set.import_error := 'import.item.invalid.circ_modifier';
2519                     attr_set.error_detail := tmp_attr_set.circ_mod;
2520                     RETURN NEXT attr_set; CONTINUE;
2521                 END IF;
2522             END IF;
2523
2524             IF tmp_attr_set.circ_as != '' THEN
2525                 SELECT code INTO attr_set.circ_as_type FROM config.coded_value_map WHERE ctype = 'item_type' AND code = tmp_attr_set.circ_as;
2526                 IF NOT FOUND THEN
2527                     attr_set.import_error := 'import.item.invalid.circ_as_type';
2528                     attr_set.error_detail := tmp_attr_set.circ_as;
2529                     RETURN NEXT attr_set; CONTINUE;
2530                 END IF;
2531             END IF;
2532
2533             IF COALESCE(tmp_attr_set.cl, '') = '' THEN
2534                 -- no location specified, see if we should apply a default
2535
2536                 SELECT INTO attr_set.location TRIM(BOTH '"' FROM value)
2537                     FROM actor.org_unit_ancestor_setting(
2538                         'vandelay.item.copy_location.default',
2539                         attr_set.owning_lib
2540                     );
2541
2542                 -- make sure the value from the org setting is still valid
2543                 PERFORM 1 FROM asset.copy_location WHERE id = attr_set.location;
2544                 IF NOT FOUND THEN
2545                     attr_set.import_error := 'import.item.invalid.location';
2546                     attr_set.error_detail := tmp_attr_set.cs;
2547                     RETURN NEXT attr_set; CONTINUE;
2548                 END IF;
2549             ELSE
2550
2551                 -- search up the org unit tree for a matching copy location
2552                 WITH RECURSIVE anscestor_depth AS (
2553                     SELECT  ou.id,
2554                         out.depth AS depth,
2555                         ou.parent_ou
2556                     FROM  actor.org_unit ou
2557                         JOIN actor.org_unit_type out ON (out.id = ou.ou_type)
2558                     WHERE ou.id = COALESCE(attr_set.owning_lib, attr_set.circ_lib)
2559                         UNION ALL
2560                     SELECT  ou.id,
2561                         out.depth,
2562                         ou.parent_ou
2563                     FROM  actor.org_unit ou
2564                         JOIN actor.org_unit_type out ON (out.id = ou.ou_type)
2565                         JOIN anscestor_depth ot ON (ot.parent_ou = ou.id)
2566                 ) SELECT  cpl.id INTO attr_set.location
2567                     FROM  anscestor_depth a
2568                         JOIN asset.copy_location cpl ON (cpl.owning_lib = a.id)
2569                     WHERE LOWER(cpl.name) = LOWER(tmp_attr_set.cl)
2570                     ORDER BY a.depth DESC
2571                     LIMIT 1;
2572
2573                 IF NOT FOUND THEN
2574                     attr_set.import_error := 'import.item.invalid.location';
2575                     attr_set.error_detail := tmp_attr_set.cs;
2576                     RETURN NEXT attr_set; CONTINUE;
2577                 END IF;
2578             END IF;
2579
2580             attr_set.circulate      :=
2581                 LOWER( SUBSTRING( tmp_attr_set.circ, 1, 1)) IN ('t','y','1')
2582                 OR LOWER(tmp_attr_set.circ) = 'circulating'; -- BOOL
2583
2584             attr_set.deposit        :=
2585                 LOWER( SUBSTRING( tmp_attr_set.dep, 1, 1 ) ) IN ('t','y','1')
2586                 OR LOWER(tmp_attr_set.dep) = 'deposit'; -- BOOL
2587
2588             attr_set.holdable       :=
2589                 LOWER( SUBSTRING( tmp_attr_set.hold, 1, 1 ) ) IN ('t','y','1')
2590                 OR LOWER(tmp_attr_set.hold) = 'holdable'; -- BOOL
2591
2592             attr_set.opac_visible   :=
2593                 LOWER( SUBSTRING( tmp_attr_set.opac_vis, 1, 1 ) ) IN ('t','y','1')
2594                 OR LOWER(tmp_attr_set.opac_vis) = 'visible'; -- BOOL
2595
2596             attr_set.ref            :=
2597                 LOWER( SUBSTRING( tmp_attr_set.r, 1, 1 ) ) IN ('t','y','1')
2598                 OR LOWER(tmp_attr_set.r) = 'reference'; -- BOOL
2599
2600             attr_set.call_number    := tmp_attr_set.cn; -- TEXT
2601             attr_set.barcode        := tmp_attr_set.bc; -- TEXT,
2602             attr_set.alert_message  := tmp_attr_set.amessage; -- TEXT,
2603             attr_set.pub_note       := tmp_attr_set.note; -- TEXT,
2604             attr_set.priv_note      := tmp_attr_set.pnote; -- TEXT,
2605             attr_set.alert_message  := tmp_attr_set.amessage; -- TEXT,
2606             attr_set.internal_id    := tmp_attr_set.internal_id::BIGINT;
2607             attr_set.stat_cat_data  := tmp_attr_set.stat_cat_data; -- TEXT,
2608             attr_set.parts_data     := tmp_attr_set.parts_data; -- TEXT,
2609
2610             RETURN NEXT attr_set;
2611
2612         END LOOP;
2613
2614     END IF;
2615
2616     RETURN;
2617
2618 END;
2619 $$ LANGUAGE PLPGSQL;
2620
2621 CREATE OR REPLACE FUNCTION vandelay.ingest_bib_items ( ) RETURNS TRIGGER AS $func$
2622 DECLARE
2623     attr_def    BIGINT;
2624     item_data   vandelay.import_item%ROWTYPE;
2625 BEGIN
2626
2627     IF TG_OP IN ('INSERT','UPDATE') AND NEW.imported_as IS NOT NULL THEN
2628         RETURN NEW;
2629     END IF;
2630
2631     SELECT item_attr_def INTO attr_def FROM vandelay.bib_queue WHERE id = NEW.queue;
2632
2633     FOR item_data IN SELECT * FROM vandelay.ingest_items( NEW.id::BIGINT, attr_def ) LOOP
2634         INSERT INTO vandelay.import_item (
2635             record,
2636             definition,
2637             owning_lib,
2638             circ_lib,
2639             call_number,
2640             copy_number,
2641             status,
2642             location,
2643             circulate,
2644             deposit,
2645             deposit_amount,
2646             ref,
2647             holdable,
2648             price,
2649             barcode,
2650             circ_modifier,
2651             circ_as_type,
2652             alert_message,
2653             pub_note,
2654             priv_note,
2655             internal_id,
2656             opac_visible,
2657             stat_cat_data,
2658             parts_data,
2659             import_error,
2660             error_detail
2661         ) VALUES (
2662             NEW.id,
2663             item_data.definition,
2664             item_data.owning_lib,
2665             item_data.circ_lib,
2666             item_data.call_number,
2667             item_data.copy_number,
2668             item_data.status,
2669             item_data.location,
2670             item_data.circulate,
2671             item_data.deposit,
2672             item_data.deposit_amount,
2673             item_data.ref,
2674             item_data.holdable,
2675             item_data.price,
2676             item_data.barcode,
2677             item_data.circ_modifier,
2678             item_data.circ_as_type,
2679             item_data.alert_message,
2680             item_data.pub_note,
2681             item_data.priv_note,
2682             item_data.internal_id,
2683             item_data.opac_visible,
2684             item_data.stat_cat_data,
2685             item_data.parts_data,
2686             item_data.import_error,
2687             item_data.error_detail
2688         );
2689     END LOOP;
2690
2691     RETURN NULL;
2692 END;
2693 $func$ LANGUAGE PLPGSQL;
2694
2695 SELECT evergreen.upgrade_deps_block_check('0963', :eg_version);
2696
2697 ALTER TABLE config.z3950_index_field_map DROP CONSTRAINT "valid_z3950_attr_type";
2698
2699 DROP FUNCTION evergreen.z3950_attr_name_is_valid(text);
2700
2701 CREATE OR REPLACE FUNCTION evergreen.z3950_attr_name_is_valid() RETURNS TRIGGER AS $func$
2702 BEGIN
2703
2704   PERFORM * FROM config.z3950_attr WHERE name = NEW.z3950_attr_type;
2705
2706   IF FOUND THEN
2707     RETURN NULL;
2708   END IF;
2709
2710   RAISE EXCEPTION '% is not a valid Z39.50 attribute type', NEW.z3950_attr_type;
2711
2712 END;
2713 $func$ LANGUAGE PLPGSQL STABLE;
2714
2715 COMMENT ON FUNCTION evergreen.z3950_attr_name_is_valid() IS $$
2716 Used by a config.z3950_index_field_map constraint trigger
2717 to verify z3950_attr_type maps.
2718 $$;
2719
2720 CREATE CONSTRAINT TRIGGER valid_z3950_attr_type AFTER INSERT OR UPDATE ON config.z3950_index_field_map
2721   DEFERRABLE INITIALLY DEFERRED FOR EACH ROW WHEN (NEW.z3950_attr_type IS NOT NULL)
2722   EXECUTE PROCEDURE evergreen.z3950_attr_name_is_valid();
2723
2724 SELECT evergreen.upgrade_deps_block_check('0964', :eg_version);
2725
2726 INSERT INTO config.coded_value_map
2727     (id, ctype, code, opac_visible, value, search_label) VALUES
2728 (712, 'search_format', 'electronic', FALSE,
2729     oils_i18n_gettext(712, 'Electronic', 'ccvm', 'value'),
2730     oils_i18n_gettext(712, 'Electronic', 'ccvm', 'search_label'));
2731
2732 INSERT INTO config.composite_attr_entry_definition
2733     (coded_value, definition) VALUES
2734 (712, '[{"_attr":"item_form","_val":"s"},{"_attr":"item_form","_val":"o"}]');
2735
2736
2737 SELECT evergreen.upgrade_deps_block_check('0965', :eg_version);
2738
2739 UPDATE action_trigger.event_definition SET template =
2740 $$
2741 [%- USE date -%]
2742 [%- SET user = target.0.usr -%]
2743 [%- SET lib = target.0.circ_lib -%]
2744 [%- SET lib_addr = target.0.circ_lib.billing_address -%]
2745 [%- SET hours = lib.hours_of_operation -%]
2746 <div>
2747     <style> li { padding: 8px; margin 5px; }</style>
2748     <div>[% date.format %]</div>
2749     <div>[% lib.name %]</div>
2750     <div>[% lib_addr.street1 %] [% lib_addr.street2 %]</div>
2751     <div>[% lib_addr.city %], [% lib_addr.state %] [% lib_addr.post_code %]</div>
2752     <div>[% lib.phone %]</div>
2753     <br/>
2754
2755     [% user.family_name %], [% user.first_given_name %]
2756     <ol>
2757     [% FOR circ IN target %]
2758         [%-
2759             SET idx = loop.count - 1;
2760             SET udata =  user_data.$idx
2761         -%]
2762         <li>
2763             <div>[% helpers.get_copy_bib_basics(circ.target_copy.id).title %]</div>
2764             <div>Barcode: [% circ.target_copy.barcode %]</div>
2765             [% IF user_data.renewal_failure %]
2766                 <div style='color:red;'>Renewal Failed</div>
2767             [% ELSE %]
2768                 <div>Due Date: [% date.format(helpers.format_date(circ.due_date), '%Y-%m-%d') %]</div>
2769             [% END %]
2770         </li>
2771     [% END %]
2772     </ol>
2773     
2774     <div>
2775         Library Hours
2776         [%- BLOCK format_time; date.format(time _ ' 1/1/1000', format='%I:%M %p'); END -%]
2777         <div>
2778             Monday 
2779             [% PROCESS format_time time = hours.dow_0_open %] 
2780             [% PROCESS format_time time = hours.dow_0_close %] 
2781         </div>
2782         <div>
2783             Tuesday 
2784             [% PROCESS format_time time = hours.dow_1_open %] 
2785             [% PROCESS format_time time = hours.dow_1_close %] 
2786         </div>
2787         <div>
2788             Wednesday 
2789             [% PROCESS format_time time = hours.dow_2_open %] 
2790             [% PROCESS format_time time = hours.dow_2_close %] 
2791         </div>
2792         <div>
2793             Thursday
2794             [% PROCESS format_time time = hours.dow_3_open %] 
2795             [% PROCESS format_time time = hours.dow_3_close %] 
2796         </div>
2797         <div>
2798             Friday
2799             [% PROCESS format_time time = hours.dow_4_open %] 
2800             [% PROCESS format_time time = hours.dow_4_close %] 
2801         </div>
2802         <div>
2803             Saturday
2804             [% PROCESS format_time time = hours.dow_5_open %] 
2805             [% PROCESS format_time time = hours.dow_5_close %] 
2806         </div>
2807         <div>
2808             Sunday 
2809             [% PROCESS format_time time = hours.dow_6_open %] 
2810             [% PROCESS format_time time = hours.dow_6_close %] 
2811         </div>
2812     </div>
2813 </div>
2814 $$
2815 WHERE id = 10 AND template =
2816 $$
2817 [%- USE date -%]
2818 [%- SET user = target.0.usr -%]
2819 [%- SET lib = target.0.circ_lib -%]
2820 [%- SET lib_addr = target.0.circ_lib.billing_address -%]
2821 [%- SET hours = lib.hours_of_operation -%]
2822 <div>
2823     <style> li { padding: 8px; margin 5px; }</style>
2824     <div>[% date.format %]</div>
2825     <div>[% lib.name %]</div>
2826     <div>[% lib_addr.street1 %] [% lib_addr.street2 %]</div>
2827     <div>[% lib_addr.city %], [% lib_addr.state %] [% lb_addr.post_code %]</div>
2828     <div>[% lib.phone %]</div>
2829     <br/>
2830
2831     [% user.family_name %], [% user.first_given_name %]
2832     <ol>
2833     [% FOR circ IN target %]
2834         [%-
2835             SET idx = loop.count - 1;
2836             SET udata =  user_data.$idx
2837         -%]
2838         <li>
2839             <div>[% helpers.get_copy_bib_basics(circ.target_copy.id).title %]</div>
2840             <div>Barcode: [% circ.target_copy.barcode %]</div>
2841             [% IF user_data.renewal_failure %]
2842                 <div style='color:red;'>Renewal Failed</div>
2843             [% ELSE %]
2844                 <div>Due Date: [% date.format(helpers.format_date(circ.due_date), '%Y-%m-%d') %]</div>
2845             [% END %]
2846         </li>
2847     [% END %]
2848     </ol>
2849     
2850     <div>
2851         Library Hours
2852         [%- BLOCK format_time; date.format(time _ ' 1/1/1000', format='%I:%M %p'); END -%]
2853         <div>
2854             Monday 
2855             [% PROCESS format_time time = hours.dow_0_open %] 
2856             [% PROCESS format_time time = hours.dow_0_close %] 
2857         </div>
2858         <div>
2859             Tuesday 
2860             [% PROCESS format_time time = hours.dow_1_open %] 
2861             [% PROCESS format_time time = hours.dow_1_close %] 
2862         </div>
2863         <div>
2864             Wednesday 
2865             [% PROCESS format_time time = hours.dow_2_open %] 
2866             [% PROCESS format_time time = hours.dow_2_close %] 
2867         </div>
2868         <div>
2869             Thursday
2870             [% PROCESS format_time time = hours.dow_3_open %] 
2871             [% PROCESS format_time time = hours.dow_3_close %] 
2872         </div>
2873         <div>
2874             Friday
2875             [% PROCESS format_time time = hours.dow_4_open %] 
2876             [% PROCESS format_time time = hours.dow_4_close %] 
2877         </div>
2878         <div>
2879             Saturday
2880             [% PROCESS format_time time = hours.dow_5_open %] 
2881             [% PROCESS format_time time = hours.dow_5_close %] 
2882         </div>
2883         <div>
2884             Sunday 
2885             [% PROCESS format_time time = hours.dow_6_open %] 
2886             [% PROCESS format_time time = hours.dow_6_close %] 
2887         </div>
2888     </div>
2889 </div>
2890 $$;
2891
2892 SELECT evergreen.upgrade_deps_block_check('0966', :eg_version); -- miker/jpringle/gmcharlt
2893
2894 -- Allow NULL post-normalization sorters
2895 CREATE OR REPLACE FUNCTION metabib.reingest_record_attributes (rid BIGINT, pattr_list TEXT[] DEFAULT NULL, prmarc TEXT DEFAULT NULL, rdeleted BOOL DEFAULT TRUE) RETURNS VOID AS $func$
2896 DECLARE
2897     transformed_xml TEXT;
2898     rmarc           TEXT := prmarc;
2899     tmp_val         TEXT;
2900     prev_xfrm       TEXT;
2901     normalizer      RECORD;
2902     xfrm            config.xml_transform%ROWTYPE;
2903     attr_vector     INT[] := '{}'::INT[];
2904     attr_vector_tmp INT[];
2905     attr_list       TEXT[] := pattr_list;
2906     attr_value      TEXT[];
2907     norm_attr_value TEXT[];
2908     tmp_xml         TEXT;
2909     attr_def        config.record_attr_definition%ROWTYPE;
2910     ccvm_row        config.coded_value_map%ROWTYPE;
2911 BEGIN
2912
2913     IF attr_list IS NULL OR rdeleted THEN -- need to do the full dance on INSERT or undelete
2914         SELECT ARRAY_AGG(name) INTO attr_list FROM config.record_attr_definition;
2915     END IF;
2916
2917     IF rmarc IS NULL THEN
2918         SELECT marc INTO rmarc FROM biblio.record_entry WHERE id = rid;
2919     END IF;
2920
2921     FOR attr_def IN SELECT * FROM config.record_attr_definition WHERE NOT composite AND name = ANY( attr_list ) ORDER BY format LOOP
2922
2923         attr_value := '{}'::TEXT[];
2924         norm_attr_value := '{}'::TEXT[];
2925         attr_vector_tmp := '{}'::INT[];
2926
2927         SELECT * INTO ccvm_row FROM config.coded_value_map c WHERE c.ctype = attr_def.name LIMIT 1; 
2928
2929         -- tag+sf attrs only support SVF
2930         IF attr_def.tag IS NOT NULL THEN -- tag (and optional subfield list) selection
2931             SELECT  ARRAY[ARRAY_TO_STRING(ARRAY_AGG(value), COALESCE(attr_def.joiner,' '))] INTO attr_value
2932               FROM  (SELECT * FROM metabib.full_rec ORDER BY tag, subfield) AS x
2933               WHERE record = rid
2934                     AND tag LIKE attr_def.tag
2935                     AND CASE
2936                         WHEN attr_def.sf_list IS NOT NULL 
2937                             THEN POSITION(subfield IN attr_def.sf_list) > 0
2938                         ELSE TRUE
2939                     END
2940               GROUP BY tag
2941               ORDER BY tag
2942               LIMIT 1;
2943
2944         ELSIF attr_def.fixed_field IS NOT NULL THEN -- a named fixed field, see config.marc21_ff_pos_map.fixed_field
2945             attr_value := vandelay.marc21_extract_fixed_field_list(rmarc, attr_def.fixed_field);
2946
2947             IF NOT attr_def.multi THEN
2948                 attr_value := ARRAY[attr_value[1]];
2949             END IF;
2950
2951         ELSIF attr_def.xpath IS NOT NULL THEN -- and xpath expression
2952
2953             SELECT INTO xfrm * FROM config.xml_transform WHERE name = attr_def.format;
2954         
2955             -- See if we can skip the XSLT ... it's expensive
2956             IF prev_xfrm IS NULL OR prev_xfrm <> xfrm.name THEN
2957                 -- Can't skip the transform
2958                 IF xfrm.xslt <> '---' THEN
2959                     transformed_xml := oils_xslt_process(rmarc,xfrm.xslt);
2960                 ELSE
2961                     transformed_xml := rmarc;
2962                 END IF;
2963     
2964                 prev_xfrm := xfrm.name;
2965             END IF;
2966
2967             IF xfrm.name IS NULL THEN
2968                 -- just grab the marcxml (empty) transform
2969                 SELECT INTO xfrm * FROM config.xml_transform WHERE xslt = '---' LIMIT 1;
2970                 prev_xfrm := xfrm.name;
2971             END IF;
2972
2973             FOR tmp_xml IN SELECT UNNEST(oils_xpath(attr_def.xpath, transformed_xml, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]])) LOOP
2974                 tmp_val := oils_xpath_string(
2975                                 '//*',
2976                                 tmp_xml,
2977                                 COALESCE(attr_def.joiner,' '),
2978                                 ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]]
2979                             );
2980                 IF tmp_val IS NOT NULL AND BTRIM(tmp_val) <> '' THEN
2981                     attr_value := attr_value || tmp_val;
2982                     EXIT WHEN NOT attr_def.multi;
2983                 END IF;
2984             END LOOP;
2985
2986         ELSIF attr_def.phys_char_sf IS NOT NULL THEN -- a named Physical Characteristic, see config.marc21_physical_characteristic_*_map
2987             SELECT  ARRAY_AGG(m.value) INTO attr_value
2988               FROM  vandelay.marc21_physical_characteristics(rmarc) v
2989                     LEFT JOIN config.marc21_physical_characteristic_value_map m ON (m.id = v.value)
2990               WHERE v.subfield = attr_def.phys_char_sf AND (m.value IS NOT NULL AND BTRIM(m.value) <> '')
2991                     AND ( ccvm_row.id IS NULL OR ( ccvm_row.id IS NOT NULL AND v.id IS NOT NULL) );
2992
2993             IF NOT attr_def.multi THEN
2994                 attr_value := ARRAY[attr_value[1]];
2995             END IF;
2996
2997         END IF;
2998
2999                 -- apply index normalizers to attr_value
3000         FOR tmp_val IN SELECT value FROM UNNEST(attr_value) x(value) LOOP
3001             FOR normalizer IN
3002                 SELECT  n.func AS func,
3003                         n.param_count AS param_count,
3004                         m.params AS params
3005                   FROM  config.index_normalizer n
3006                         JOIN config.record_attr_index_norm_map m ON (m.norm = n.id)
3007                   WHERE attr = attr_def.name
3008                   ORDER BY m.pos LOOP
3009                     EXECUTE 'SELECT ' || normalizer.func || '(' ||
3010                     COALESCE( quote_literal( tmp_val ), 'NULL' ) ||
3011                         CASE
3012                             WHEN normalizer.param_count > 0
3013                                 THEN ',' || REPLACE(REPLACE(BTRIM(normalizer.params,'[]'),E'\'',E'\\\''),E'"',E'\'')
3014                                 ELSE ''
3015                             END ||
3016                     ')' INTO tmp_val;
3017
3018             END LOOP;
3019             IF tmp_val IS NOT NULL AND tmp_val <> '' THEN
3020                 -- note that a string that contains only blanks
3021                 -- is a valid value for some attributes
3022                 norm_attr_value := norm_attr_value || tmp_val;
3023             END IF;
3024         END LOOP;
3025         
3026         IF attr_def.filter THEN
3027             -- Create unknown uncontrolled values and find the IDs of the values
3028             IF ccvm_row.id IS NULL THEN
3029                 FOR tmp_val IN SELECT value FROM UNNEST(norm_attr_value) x(value) LOOP
3030                     IF tmp_val IS NOT NULL AND BTRIM(tmp_val) <> '' THEN
3031                         BEGIN -- use subtransaction to isolate unique constraint violations
3032                             INSERT INTO metabib.uncontrolled_record_attr_value ( attr, value ) VALUES ( attr_def.name, tmp_val );
3033                         EXCEPTION WHEN unique_violation THEN END;
3034                     END IF;
3035                 END LOOP;
3036
3037                 SELECT ARRAY_AGG(id) INTO attr_vector_tmp FROM metabib.uncontrolled_record_attr_value WHERE attr = attr_def.name AND value = ANY( norm_attr_value );
3038             ELSE
3039                 SELECT ARRAY_AGG(id) INTO attr_vector_tmp FROM config.coded_value_map WHERE ctype = attr_def.name AND code = ANY( norm_attr_value );
3040             END IF;
3041
3042             -- Add the new value to the vector
3043             attr_vector := attr_vector || attr_vector_tmp;
3044         END IF;
3045
3046         IF attr_def.sorter THEN
3047             DELETE FROM metabib.record_sorter WHERE source = rid AND attr = attr_def.name;
3048             IF norm_attr_value[1] IS NOT NULL THEN
3049                 INSERT INTO metabib.record_sorter (source, attr, value) VALUES (rid, attr_def.name, norm_attr_value[1]);
3050             END IF;
3051         END IF;
3052
3053     END LOOP;
3054
3055 /* We may need to rewrite the vlist to contain
3056    the intersection of new values for requested
3057    attrs and old values for ignored attrs. To
3058    do this, we take the old attr vlist and
3059    subtract any values that are valid for the
3060    requested attrs, and then add back the new
3061    set of attr values. */
3062
3063     IF ARRAY_LENGTH(pattr_list, 1) > 0 THEN 
3064         SELECT vlist INTO attr_vector_tmp FROM metabib.record_attr_vector_list WHERE source = rid;
3065         SELECT attr_vector_tmp - ARRAY_AGG(id::INT) INTO attr_vector_tmp FROM metabib.full_attr_id_map WHERE attr = ANY (pattr_list);
3066         attr_vector := attr_vector || attr_vector_tmp;
3067     END IF;
3068
3069     -- On to composite attributes, now that the record attrs have been pulled.  Processed in name order, so later composite
3070     -- attributes can depend on earlier ones.
3071     PERFORM metabib.compile_composite_attr_cache_init();
3072     FOR attr_def IN SELECT * FROM config.record_attr_definition WHERE composite AND name = ANY( attr_list ) ORDER BY name LOOP
3073
3074         FOR ccvm_row IN SELECT * FROM config.coded_value_map c WHERE c.ctype = attr_def.name ORDER BY value LOOP
3075
3076             tmp_val := metabib.compile_composite_attr( ccvm_row.id );
3077             CONTINUE WHEN tmp_val IS NULL OR tmp_val = ''; -- nothing to do
3078
3079             IF attr_def.filter THEN
3080                 IF attr_vector @@ tmp_val::query_int THEN
3081                     attr_vector = attr_vector + intset(ccvm_row.id);
3082                     EXIT WHEN NOT attr_def.multi;
3083                 END IF;
3084             END IF;
3085
3086             IF attr_def.sorter THEN
3087                 IF attr_vector @@ tmp_val THEN
3088                     DELETE FROM metabib.record_sorter WHERE source = rid AND attr = attr_def.name;
3089                     INSERT INTO metabib.record_sorter (source, attr, value) VALUES (rid, attr_def.name, ccvm_row.code);
3090                 END IF;
3091             END IF;
3092
3093         END LOOP;
3094
3095     END LOOP;
3096
3097     IF ARRAY_LENGTH(attr_vector, 1) > 0 THEN
3098         IF rdeleted THEN -- initial insert OR revivication
3099             DELETE FROM metabib.record_attr_vector_list WHERE source = rid;
3100             INSERT INTO metabib.record_attr_vector_list (source, vlist) VALUES (rid, attr_vector);
3101         ELSE
3102             UPDATE metabib.record_attr_vector_list SET vlist = attr_vector WHERE source = rid;
3103         END IF;
3104     END IF;
3105
3106 END;
3107
3108 $func$ LANGUAGE PLPGSQL;
3109
3110 -- Correct SER and COM records, add most other subfields and make them usable as CCVMs
3111
3112 SELECT evergreen.upgrade_deps_block_check('0967', :eg_version);
3113
3114 -- Fix SER
3115 DELETE FROM config.marc21_ff_pos_map WHERE fixed_field = 'Audn' AND rec_type = 'SER';
3116
3117
3118 -- Map Fields to Record Types
3119 -- Form was already defined but missing from COM
3120 INSERT INTO config.marc21_ff_pos_map (fixed_field, tag, rec_type,start_pos, length, default_val) VALUES
3121     ('Form', '006', 'COM', 6, 1, ' '),
3122     ('Form', '008', 'COM', 23, 1, ' '),
3123
3124     ('Relf', '006', 'MAP', 1, 4, '    '),
3125     ('Relf', '008', 'MAP', 18, 4, '    '),
3126     ('Proj', '006', 'MAP', 5, 2, '  '),
3127     ('Proj', '008', 'MAP', 22, 2, '  '),
3128     ('CrTp', '006', 'MAP', 8, 1, 'a'),
3129     ('CrTp', '008', 'MAP', 25, 1, 'a'),
3130     ('SpFm', '006', 'MAP', 16, 2, '  '),
3131     ('SpFm', '008', 'MAP', 33, 2, '  '),
3132     ('Relf1', '006', 'MAP', 1, 1, ' '),
3133     ('Relf1', '008', 'MAP', 18, 1, ' '),
3134     ('Relf2', '006', 'MAP', 2, 1, ' '),
3135     ('Relf2', '008', 'MAP', 19, 1, ' '),
3136     ('Relf3', '006', 'MAP', 3, 1, ' '),
3137     ('Relf3', '008', 'MAP', 20, 1, ' '),
3138     ('Relf4', '006', 'MAP', 4, 1, ' '),
3139     ('Relf4', '008', 'MAP', 21, 1, ' '),
3140     ('SpFm1', '006', 'MAP', 16, 1, ' '),
3141     ('SpFm1', '008', 'MAP', 33, 1, ' '),
3142     ('SpFm2', '006', 'MAP', 17, 1, ' '),
3143     ('SpFm2', '008', 'MAP', 34, 1, ' '),
3144
3145     ('Comp', '006', 'REC', 1, 2, 'uu'),
3146     ('Comp', '008', 'REC', 18, 2, 'uu'),
3147     ('FMus', '006', 'REC', 3, 1, 'n'),
3148     ('FMus', '008', 'REC', 20, 1, 'n'),
3149     ('Part', '006', 'REC', 4, 1, 'n'),
3150     ('Part', '008', 'REC', 21, 1, 'n'),
3151     ('AccM', '006', 'REC', 7, 6, '      '),
3152     ('AccM', '008', 'REC', 24, 6, '      '),
3153     ('LTxt', '006', 'REC', 13, 2, '  '),
3154     ('LTxt', '008', 'REC', 30, 2, '  '),
3155     ('TrAr', '006', 'REC', 16, 1, 'n'),
3156     ('TrAr', '008', 'REC', 33, 1, 'n'),
3157     ('AccM1', '006', 'REC', 7, 1, ' '),
3158     ('AccM1', '008', 'REC', 24, 1, ' '),
3159     ('AccM2', '006', 'REC', 8, 1, ' '),
3160     ('AccM2', '008', 'REC', 25, 1, ' '),
3161     ('AccM3', '006', 'REC', 9, 1, ' '),
3162     ('AccM3', '008', 'REC', 26, 1, ' '),
3163     ('AccM4', '006', 'REC', 10, 1, ' '),
3164     ('AccM4', '008', 'REC', 27, 1, ' '),
3165     ('AccM5', '006', 'REC', 11, 1, ' '),
3166     ('AccM5', '008', 'REC', 28, 1, ' '),
3167     ('AccM6', '006', 'REC', 12, 1, ' '),
3168     ('AccM6', '008', 'REC', 29, 1, ' '),
3169     ('LTxt1', '006', 'REC', 13, 1, ' '),
3170     ('LTxt1', '008', 'REC', 30, 1, ' '),
3171     ('LTxt2', '006', 'REC', 14, 1, ' '),
3172     ('LTxt2', '008', 'REC', 31, 1, ' '),
3173
3174     ('Comp', '006', 'SCO', 1, 2, 'uu'),
3175     ('Comp', '008', 'SCO', 18, 2, 'uu'),
3176     ('FMus', '006', 'SCO', 3, 1, 'u'),
3177     ('FMus', '008', 'SCO', 20, 1, 'u'),
3178     ('Part', '006', 'SCO', 4, 1, ' '),
3179     ('Part', '008', 'SCO', 21, 1, ' '),
3180     ('AccM', '006', 'SCO', 7, 6, '      '),
3181     ('AccM', '008', 'SCO', 24, 6, '      '),
3182     ('LTxt', '006', 'SCO', 13, 2, 'n '),
3183     ('LTxt', '008', 'SCO', 30, 2, 'n '),
3184     ('TrAr', '006', 'SCO', 16, 1, ' '),
3185     ('TrAr', '008', 'SCO', 33, 1, ' '),
3186     ('AccM1', '006', 'SCO', 7, 1, ' '),
3187     ('AccM1', '008', 'SCO', 24, 1, ' '),
3188     ('AccM2', '006', 'SCO', 8, 1, ' '),
3189     ('AccM2', '008', 'SCO', 25, 1, ' '),
3190     ('AccM3', '006', 'SCO', 9, 1, ' '),
3191     ('AccM3', '008', 'SCO', 26, 1, ' '),
3192     ('AccM4', '006', 'SCO', 10, 1, ' '),
3193     ('AccM4', '008', 'SCO', 27, 1, ' '),
3194     ('AccM5', '006', 'SCO', 11, 1, ' '),
3195     ('AccM5', '008', 'SCO', 28, 1, ' '),
3196     ('AccM6', '006', 'SCO', 12, 1, ' '),
3197     ('AccM6', '008', 'SCO', 29, 1, ' '),
3198     ('LTxt1', '006', 'SCO', 13, 1, 'n'),
3199     ('LTxt1', '008', 'SCO', 30, 1, 'n'),
3200     ('LTxt2', '006', 'SCO', 14, 1, 'n'),
3201     ('LTxt2', '008', 'SCO', 31, 1, 'n'),
3202
3203     ('SrTp', '006', 'SER', 4, 1, ' '),
3204     ('SrTp', '008', 'SER', 21, 1, ' '),
3205     ('Orig', '006', 'SER', 5, 1, ' '),
3206     ('Orig', '008', 'SER', 22, 1, ' '),
3207     ('EntW', '006', 'SER', 7, 1, ' '),
3208     ('EntW', '008', 'SER', 24, 1, ' '),
3209
3210     ('Time', '006', 'VIS', 1, 3, '   '),
3211     ('Time', '008', 'VIS', 18, 3, '   '),
3212     ('Tech', '006', 'VIS', 17, 1, 'n'),
3213     ('Tech', '008', 'VIS', 34, 1, 'n'),
3214         
3215         ('Ills1', '006', 'BKS', 1, 1, ' '),
3216     ('Ills1', '008', 'BKS', 18, 1, ' '),
3217     ('Ills2', '006', 'BKS', 2, 1, ' '),
3218     ('Ills2', '008', 'BKS', 19, 1, ' '),
3219     ('Ills3', '006', 'BKS', 3, 1, ' '),
3220     ('Ills3', '008', 'BKS', 20, 1, ' '),
3221     ('Ills4', '006', 'BKS', 4, 1, ' '),
3222     ('Ills4', '008', 'BKS', 21, 1, ' '),
3223     ('Cont1', '006', 'BKS', 7, 1, ' '),
3224     ('Cont1', '008', 'BKS', 24, 1, ' '),
3225     ('Cont2', '006', 'BKS', 8, 1, ' '),
3226     ('Cont2', '008', 'BKS', 25, 1, ' '),
3227     ('Cont3', '006', 'BKS', 9, 1, ' '),
3228     ('Cont3', '008', 'BKS', 26, 1, ' '),
3229     ('Cont4', '006', 'BKS', 10, 1, ' '),
3230     ('Cont4', '008', 'BKS', 27, 1, ' '),
3231
3232     ('Cont1', '006', 'SER', 8, 1, ' '),
3233     ('Cont1', '008', 'SER', 25, 1, ' '),
3234     ('Cont2', '006', 'SER', 9, 1, ' '),
3235     ('Cont2', '008', 'SER', 26, 1, ' '),
3236     ('Cont3', '006', 'SER', 10, 1, ' '),
3237     ('Cont3', '008', 'SER', 27, 1, ' ');
3238
3239
3240 -- Add record_attr_definitions
3241 -- The xxx1,2,etc. are for multi-position single character code fields.
3242 INSERT INTO config.record_attr_definition (name,label,fixed_field) VALUES
3243     ('accm','AccM','AccM'),
3244     ('comp','Comp','Comp'),
3245     ('crtp','CrTp','CrTp'),
3246     ('entw','EntW','EntW'),
3247     ('cont','Cont','Cont'),
3248     ('fmus','FMus','FMus'),
3249     ('ltxt','LTxt','LTxt'),
3250     ('orig','Orig','Orig'),
3251     ('part','Part','Part'),
3252     ('proj','Proj','Proj'),
3253     ('relf','Relf','Relf'),
3254     ('spfm','SpFm','SpFm'),
3255     ('srtp','SrTp','SrTp'),
3256     ('tech','Tech','Tech'),
3257     ('trar','TrAr','TrAr'),
3258     ('accm1','AccM(1)','AccM1'),
3259     ('accm2','AccM(2)','AccM2'),
3260     ('accm3','AccM(3)','AccM3'),
3261     ('accm4','AccM(4)','AccM4'),
3262     ('accm5','AccM(5)','AccM5'),
3263     ('accm6','AccM(6)','AccM6'),
3264     ('cont1','Cont(1)','Cont1'),
3265     ('cont2','Cont(2)','Cont2'),
3266     ('cont3','Cont(3)','Cont3'),
3267     ('cont4','Cont(4)','Cont4'),
3268     ('ills1','Ills(1)','Ills1'),
3269     ('ills2','Ills(2)','Ills2'),
3270     ('ills3','Ills(3)','Ills3'),
3271     ('ills4','Ills(4)','Ills4'),
3272     ('ltxt1','LTxt(1)','LTxt1'),
3273     ('ltxt2','LTxt(2)','LTxt2'),
3274     ('relf1','Relf(1)','Relf1'),
3275     ('relf2','Relf(2)','Relf2'),
3276     ('relf3','Relf(3)','Relf3'),
3277     ('relf4','Relf(4)','Relf4'),
3278     ('spfm1','SpFm(1)','SpFm1'),
3279     ('spfm2','SpFm(2)','SpFm2');
3280
3281 UPDATE config.record_attr_definition SET composite = TRUE WHERE name IN ('accm', 'cont', 'ills', 'ltxt', 'relf', 'spfm');
3282
3283 -- "Next" id for stock config.coded_value_map is 634 as of 7/16/15, but there's an incoming patch that takes 634-711
3284 INSERT INTO config.coded_value_map (id, ctype, code, value) VALUES
3285     (1735, 'accm', ' ',                 oils_i18n_gettext('1735', 'No accompanying matter', 'ccvm', 'value')),
3286     (713, 'accm', 'a',                  oils_i18n_gettext('713', 'Discography', 'ccvm', 'value')),
3287     (714, 'accm', 'b',                  oils_i18n_gettext('714', 'Bibliography', 'ccvm', 'value')),
3288     (715, 'accm', 'c',                  oils_i18n_gettext('715', 'Thematic index', 'ccvm', 'value')),
3289     (716, 'accm', 'd',                  oils_i18n_gettext('716', 'Libretto or text', 'ccvm', 'value')),
3290     (717, 'accm', 'e',                  oils_i18n_gettext('717', 'Biography of composer or author', 'ccvm', 'value')),
3291     (718, 'accm', 'f',                  oils_i18n_gettext('718', 'Biography or performer or history of ensemble', 'ccvm', 'value')),
3292     (719, 'accm', 'g',                  oils_i18n_gettext('719', 'Technical and/or historical information on instruments', 'ccvm', 'value')),
3293     (720, 'accm', 'h',                  oils_i18n_gettext('720', 'Technical information on music', 'ccvm', 'value')),
3294     (721, 'accm', 'i',                  oils_i18n_gettext('721', 'Historical information', 'ccvm', 'value')),
3295     (722, 'accm', 'k',                  oils_i18n_gettext('722', 'Ethnological information', 'ccvm', 'value')),
3296     (723, 'accm', 'r',                  oils_i18n_gettext('723', 'Instructional materials', 'ccvm', 'value')),
3297     (724, 'accm', 's',                  oils_i18n_gettext('724', 'Music', 'ccvm', 'value')),
3298     (725, 'accm', 'z',                  oils_i18n_gettext('725', 'Other accompanying matter', 'ccvm', 'value')),
3299         
3300     (726, 'comp', '  ',                 oils_i18n_gettext('726', 'No information supplied', 'ccvm', 'value')),
3301     (727, 'comp', 'an',                 oils_i18n_gettext('727', 'Anthems', 'ccvm', 'value')),
3302     (728, 'comp', 'bd',                 oils_i18n_gettext('728', 'Ballads', 'ccvm', 'value')),
3303     (729, 'comp', 'bt',                 oils_i18n_gettext('729', 'Ballets', 'ccvm', 'value')),
3304     (730, 'comp', 'bg',                 oils_i18n_gettext('730', 'Bluegrass music', 'ccvm', 'value')),
3305     (731, 'comp', 'bl',                 oils_i18n_gettext('731', 'Blues', 'ccvm', 'value')),
3306     (732, 'comp', 'cn',                 oils_i18n_gettext('732', 'Canons and rounds', 'ccvm', 'value')),
3307     (733, 'comp', 'ct',                 oils_i18n_gettext('733', 'Cantatas', 'ccvm', 'value')),
3308     (734, 'comp', 'cz',                 oils_i18n_gettext('734', 'Canzonas', 'ccvm', 'value')),
3309     (735, 'comp', 'cr',                 oils_i18n_gettext('735', 'Carols', 'ccvm', 'value')),
3310     (736, 'comp', 'ca',                 oils_i18n_gettext('736', 'Chaconnes', 'ccvm', 'value')),
3311     (737, 'comp', 'cs',                 oils_i18n_gettext('737', 'Chance compositions', 'ccvm', 'value')),
3312     (738, 'comp', 'cp',                 oils_i18n_gettext('738', 'Chansons, Polyphonic', 'ccvm', 'value')),
3313     (739, 'comp', 'cc',                 oils_i18n_gettext('739', 'Chant, Christian', 'ccvm', 'value')),
3314     (740, 'comp', 'cb',                 oils_i18n_gettext('740', 'Chants, other', 'ccvm', 'value')),
3315     (741, 'comp', 'cl',                 oils_i18n_gettext('741', 'Chorale preludes', 'ccvm', 'value')),
3316     (742, 'comp', 'ch',                 oils_i18n_gettext('742', 'Chorales', 'ccvm', 'value')),
3317     (743, 'comp', 'cg',                 oils_i18n_gettext('743', 'Concerti grossi', 'ccvm', 'value')),
3318     (744, 'comp', 'co',                 oils_i18n_gettext('744', 'Concertos', 'ccvm', 'value')),
3319     (745, 'comp', 'cy',                 oils_i18n_gettext('745', 'Country music', 'ccvm', 'value')),
3320     (746, 'comp', 'df',                 oils_i18n_gettext('746', 'Dance forms', 'ccvm', 'value')),
3321     (747, 'comp', 'dv',                 oils_i18n_gettext('747', 'Divertimentos, serenades, cassations, divertissements, and notturni', 'ccvm', 'value')),
3322     (748, 'comp', 'ft',                 oils_i18n_gettext('748', 'Fantasias', 'ccvm', 'value')),
3323     (749, 'comp', 'fl',                 oils_i18n_gettext('749', 'Flamenco', 'ccvm', 'value')),
3324     (750, 'comp', 'fm',                 oils_i18n_gettext('750', 'Folk music', 'ccvm', 'value')),
3325     (751, 'comp', 'fg',                 oils_i18n_gettext('751', 'Fugues', 'ccvm', 'value')),
3326     (752, 'comp', 'gm',                 oils_i18n_gettext('752', 'Gospel music', 'ccvm', 'value')),
3327     (753, 'comp', 'hy',                 oils_i18n_gettext('753', 'Hymns', 'ccvm', 'value')),
3328     (754, 'comp', 'jz',                 oils_i18n_gettext('754', 'Jazz', 'ccvm', 'value')),
3329     (755, 'comp', 'md',                 oils_i18n_gettext('755', 'Madrigals', 'ccvm', 'value')),
3330     (756, 'comp', 'mr',                 oils_i18n_gettext('756', 'Marches', 'ccvm', 'value')),
3331     (757, 'comp', 'ms',                 oils_i18n_gettext('757', 'Masses', 'ccvm', 'value')),
3332     (758, 'comp', 'mz',                 oils_i18n_gettext('758', 'Mazurkas', 'ccvm', 'value')),
3333     (759, 'comp', 'mi',                 oils_i18n_gettext('759', 'Minuets', 'ccvm', 'value')),
3334     (760, 'comp', 'mo',                 oils_i18n_gettext('760', 'Motets', 'ccvm', 'value')),
3335     (761, 'comp', 'mp',                 oils_i18n_gettext('761', 'Motion picture music', 'ccvm', 'value')),
3336     (762, 'comp', 'mu',                 oils_i18n_gettext('762', 'Multiple forms', 'ccvm', 'value')),
3337     (763, 'comp', 'mc',                 oils_i18n_gettext('763', 'Musical reviews and comedies', 'ccvm', 'value')),
3338     (764, 'comp', 'nc',                 oils_i18n_gettext('764', 'Nocturnes', 'ccvm', 'value')),
3339     (765, 'comp', 'nn',                 oils_i18n_gettext('765', 'Not applicable', 'ccvm', 'value')),
3340     (766, 'comp', 'op',                 oils_i18n_gettext('766', 'Operas', 'ccvm', 'value')),
3341     (767, 'comp', 'or',                 oils_i18n_gettext('767', 'Oratorios', 'ccvm', 'value')),
3342     (768, 'comp', 'ov',                 oils_i18n_gettext('768', 'Overtures', 'ccvm', 'value')),
3343     (769, 'comp', 'pt',                 oils_i18n_gettext('769', 'Part-songs', 'ccvm', 'value')),
3344     (770, 'comp', 'ps',                 oils_i18n_gettext('770', 'Passacaglias', 'ccvm', 'value')),
3345     (771, 'comp', 'pm',                 oils_i18n_gettext('771', 'Passion music', 'ccvm', 'value')),
3346     (772, 'comp', 'pv',                 oils_i18n_gettext('772', 'Pavans', 'ccvm', 'value')),
3347     (773, 'comp', 'po',                 oils_i18n_gettext('773', 'Polonaises', 'ccvm', 'value')),
3348     (774, 'comp', 'pp',                 oils_i18n_gettext('774', 'Popular music', 'ccvm', 'value')),
3349     (775, 'comp', 'pr',                 oils_i18n_gettext('775', 'Preludes', 'ccvm', 'value')),
3350     (776, 'comp', 'pg',                 oils_i18n_gettext('776', 'Program music', 'ccvm', 'value')),
3351     (777, 'comp', 'rg',                 oils_i18n_gettext('777', 'Ragtime music', 'ccvm', 'value')),
3352     (778, 'comp', 'rq',                 oils_i18n_gettext('778', 'Requiems', 'ccvm', 'value')),
3353     (779, 'comp', 'rp',                 oils_i18n_gettext('779', 'Rhapsodies', 'ccvm', 'value')),
3354     (780, 'comp', 'ri',                 oils_i18n_gettext('780', 'Ricercars', 'ccvm', 'value')),
3355     (781, 'comp', 'rc',                 oils_i18n_gettext('781', 'Rock music', 'ccvm', 'value')),
3356     (782, 'comp', 'rd',                 oils_i18n_gettext('782', 'Rondos', 'ccvm', 'value')),
3357     (783, 'comp', 'sn',                 oils_i18n_gettext('783', 'Sonatas', 'ccvm', 'value')),
3358     (784, 'comp', 'sg',                 oils_i18n_gettext('784', 'Songs', 'ccvm', 'value')),
3359     (785, 'comp', 'sd',                 oils_i18n_gettext('785', 'Square dance music', 'ccvm', 'value')),
3360     (786, 'comp', 'st',                 oils_i18n_gettext('786', 'Studies and exercises', 'ccvm', 'value')),
3361     (787, 'comp', 'su',                 oils_i18n_gettext('787', 'Suites', 'ccvm', 'value')),
3362     (788, 'comp', 'sp',                 oils_i18n_gettext('788', 'Symphonic poems', 'ccvm', 'value')),
3363     (789, 'comp', 'sy',                 oils_i18n_gettext('789', 'Symphonies', 'ccvm', 'value')),
3364     (790, 'comp', 'tl',                 oils_i18n_gettext('790', 'Teatro lirico', 'ccvm', 'value')),
3365     (791, 'comp', 'tc',                 oils_i18n_gettext('791', 'Toccatas', 'ccvm', 'value')),
3366     (792, 'comp', 'ts',                 oils_i18n_gettext('792', 'Trio-sonatas', 'ccvm', 'value')),
3367     (793, 'comp', 'uu',                 oils_i18n_gettext('793', 'Unknown', 'ccvm', 'value')),
3368     (794, 'comp', 'vi',                 oils_i18n_gettext('794', 'Villancicos', 'ccvm', 'value')),
3369     (795, 'comp', 'vr',                 oils_i18n_gettext('795', 'Variations', 'ccvm', 'value')),
3370     (796, 'comp', 'wz',                 oils_i18n_gettext('796', 'Waltzes', 'ccvm', 'value')),
3371     (797, 'comp', 'za',                 oils_i18n_gettext('797', 'Zarzuelas', 'ccvm', 'value')),
3372     (798, 'comp', 'zz',                 oils_i18n_gettext('798', 'Other forms', 'ccvm', 'value')),
3373         
3374     (799, 'crtp', 'a',                  oils_i18n_gettext('799', 'Single map', 'ccvm', 'value')),
3375     (800, 'crtp', 'b',                  oils_i18n_gettext('800', 'Map series', 'ccvm', 'value')),
3376     (801, 'crtp', 'c',                  oils_i18n_gettext('801', 'Map serial', 'ccvm', 'value')),
3377     (802, 'crtp', 'd',                  oils_i18n_gettext('802', 'Globe', 'ccvm', 'value')),
3378     (803, 'crtp', 'e',                  oils_i18n_gettext('803', 'Atlas', 'ccvm', 'value')),
3379     (804, 'crtp', 'f',                  oils_i18n_gettext('804', 'Separate supplement to another work', 'ccvm', 'value')),
3380     (805, 'crtp', 'g',                  oils_i18n_gettext('805', 'Bound as part of another work', 'ccvm', 'value')),
3381     (806, 'crtp', 'u',                  oils_i18n_gettext('806', 'Unknown', 'ccvm', 'value')),
3382     (807, 'crtp', 'z',                  oils_i18n_gettext('807', 'Other', 'ccvm', 'value')),
3383         
3384     (808, 'entw', ' ',                  oils_i18n_gettext('808', 'Not specified', 'ccvm', 'value')),
3385     (809, 'entw', 'a',                  oils_i18n_gettext('809', 'Abstracts/summaries', 'ccvm', 'value')),
3386     (810, 'entw', 'b',                  oils_i18n_gettext('810', 'Bibliographies', 'ccvm', 'value')),
3387     (811, 'entw', 'c',                  oils_i18n_gettext('811', 'Catalogs', 'ccvm', 'value')),
3388     (812, 'entw', 'd',                  oils_i18n_gettext('812', 'Dictionaries', 'ccvm', 'value')),
3389     (813, 'entw', 'e',                  oils_i18n_gettext('813', 'Encyclopedias', 'ccvm', 'value')),
3390     (814, 'entw', 'f',                  oils_i18n_gettext('814', 'Handbooks', 'ccvm', 'value')),
3391     (815, 'entw', 'g',                  oils_i18n_gettext('815', 'Legal articles', 'ccvm', 'value')),
3392     (816, 'entw', 'h',                  oils_i18n_gettext('816', 'Biography', 'ccvm', 'value')),
3393     (817, 'entw', 'i',                  oils_i18n_gettext('817', 'Indexes', 'ccvm', 'value')),
3394     (818, 'entw', 'k',                  oils_i18n_gettext('818', 'Discographies', 'ccvm', 'value')),
3395     (819, 'entw', 'l',                  oils_i18n_gettext('819', 'Legislation', 'ccvm', 'value')),
3396     (820, 'entw', 'm',                  oils_i18n_gettext('820', 'Theses', 'ccvm', 'value')),
3397     (821, 'entw', 'n',                  oils_i18n_gettext('821', 'Surveys of the literature in a subject area', 'ccvm', 'value')),
3398     (822, 'entw', 'o',                  oils_i18n_gettext('822', 'Reviews', 'ccvm', 'value')),
3399     (823, 'entw', 'p',                  oils_i18n_gettext('823', 'Programmed texts', 'ccvm', 'value')),
3400     (824, 'entw', 'q',                  oils_i18n_gettext('824', 'Filmographies', 'ccvm', 'value')),
3401     (825, 'entw', 'r',                  oils_i18n_gettext('825', 'Directories', 'ccvm', 'value')),
3402     (826, 'entw', 's',                  oils_i18n_gettext('826', 'Statistics', 'ccvm', 'value')),
3403     (827, 'entw', 't',                  oils_i18n_gettext('827', 'Technical reports', 'ccvm', 'value')),
3404     (828, 'entw', 'u',                  oils_i18n_gettext('828', 'Standards/specifications', 'ccvm', 'value')),
3405     (829, 'entw', 'v',                  oils_i18n_gettext('829', 'Legal cases and case notes', 'ccvm', 'value')),
3406     (830, 'entw', 'w',                  oils_i18n_gettext('830', 'Law reports and digests', 'ccvm', 'value')),
3407     (831, 'entw', 'y',                  oils_i18n_gettext('831', 'Yearbooks', 'ccvm', 'value')),
3408     (832, 'entw', 'z',                  oils_i18n_gettext('832', 'Treaties', 'ccvm', 'value')),
3409     (833, 'entw', '5',                  oils_i18n_gettext('833', 'Calendars', 'ccvm', 'value')),
3410     (834, 'entw', '6',                  oils_i18n_gettext('834', 'Comics/graphic novels', 'ccvm', 'value')),
3411         
3412     (835, 'cont', ' ',                  oils_i18n_gettext('835', 'Not specified', 'ccvm', 'value')),
3413     (836, 'cont', 'a',                  oils_i18n_gettext('836', 'Abstracts/summaries', 'ccvm', 'value')),
3414     (837, 'cont', 'b',                  oils_i18n_gettext('837', 'Bibliographies', 'ccvm', 'value')),
3415     (838, 'cont', 'c',                  oils_i18n_gettext('838', 'Catalogs', 'ccvm', 'value')),
3416     (839, 'cont', 'd',                  oils_i18n_gettext('839', 'Dictionaries', 'ccvm', 'value')),
3417     (840, 'cont', 'e',                  oils_i18n_gettext('840', 'Encyclopedias', 'ccvm', 'value')),
3418     (841, 'cont', 'f',                  oils_i18n_gettext('841', 'Handbooks', 'ccvm', 'value')),
3419     (842, 'cont', 'g',                  oils_i18n_gettext('842', 'Legal articles', 'ccvm', 'value')),
3420     (843, 'cont', 'h',                  oils_i18n_gettext('843', 'Biography', 'ccvm', 'value')),
3421     (844, 'cont', 'i',                  oils_i18n_gettext('844', 'Indexes', 'ccvm', 'value')),
3422     (845, 'cont', 'j',                  oils_i18n_gettext('845', 'Patent document', 'ccvm', 'value')),
3423     (846, 'cont', 'k',                  oils_i18n_gettext('846', 'Discographies', 'ccvm', 'value')),
3424     (847, 'cont', 'l',                  oils_i18n_gettext('847', 'Legislation', 'ccvm', 'value')),
3425     (848, 'cont', 'm',                  oils_i18n_gettext('848', 'Theses', 'ccvm', 'value')),
3426     (849, 'cont', 'n',                  oils_i18n_gettext('849', 'Surveys of the literature in a subject area', 'ccvm', 'value')),
3427     (850, 'cont', 'o',                  oils_i18n_gettext('850', 'Reviews', 'ccvm', 'value')),
3428     (851, 'cont', 'p',                  oils_i18n_gettext('851', 'Programmed texts', 'ccvm', 'value')),
3429     (852, 'cont', 'q',                  oils_i18n_gettext('852', 'Filmographies', 'ccvm', 'value')),
3430     (853, 'cont', 'r',                  oils_i18n_gettext('853', 'Directories', 'ccvm', 'value')),
3431     (854, 'cont', 's',                  oils_i18n_gettext('854', 'Statistics', 'ccvm', 'value')),
3432     (855, 'cont', 't',                  oils_i18n_gettext('855', 'Technical reports', 'ccvm', 'value')),
3433     (856, 'cont', 'u',                  oils_i18n_gettext('856', 'Standards/specifications', 'ccvm', 'value')),
3434     (857, 'cont', 'v',                  oils_i18n_gettext('857', 'Legal cases and case notes', 'ccvm', 'value')),
3435     (858, 'cont', 'w',                  oils_i18n_gettext('858', 'Law reports and digests', 'ccvm', 'value')),
3436     (859, 'cont', 'x',                  oils_i18n_gettext('859', 'Other reports', 'ccvm', 'value')),
3437     (860, 'cont', 'y',                  oils_i18n_gettext('860', 'Yearbooks', 'ccvm', 'value')),
3438     (861, 'cont', 'z',                  oils_i18n_gettext('861', 'Treaties', 'ccvm', 'value')),
3439     (862, 'cont', '2',                  oils_i18n_gettext('862', 'Offprints', 'ccvm', 'value')),
3440     (863, 'cont', '5',                  oils_i18n_gettext('863', 'Calendars', 'ccvm', 'value')),
3441     (864, 'cont', '6',                  oils_i18n_gettext('864', 'Comics/graphic novels', 'ccvm', 'value')),
3442         
3443     (865, 'fmus', ' ',                  oils_i18n_gettext('865', 'Information not supplied', 'ccvm', 'value')),
3444     (866, 'fmus', 'a',                  oils_i18n_gettext('866', 'Full score', 'ccvm', 'value')),
3445     (867, 'fmus', 'b',                  oils_i18n_gettext('867', 'Full score, miniature or study size', 'ccvm', 'value')),
3446     (868, 'fmus', 'c',                  oils_i18n_gettext('868', 'Accompaniment reduced for keyboard', 'ccvm', 'value')),
3447     (869, 'fmus', 'd',                  oils_i18n_gettext('869', 'Voice score with accompaniment omitted', 'ccvm', 'value')),
3448     (870, 'fmus', 'e',                  oils_i18n_gettext('870', 'Condensed score or piano-conductor score', 'ccvm', 'value')),
3449     (871, 'fmus', 'g',                  oils_i18n_gettext('871', 'Close score', 'ccvm', 'value')),
3450     (872, 'fmus', 'h',                  oils_i18n_gettext('872', 'Chorus score', 'ccvm', 'value')),
3451     (873, 'fmus', 'i',                  oils_i18n_gettext('873', 'Condensed score', 'ccvm', 'value')),
3452     (874, 'fmus', 'j',                  oils_i18n_gettext('874', 'Performer-conductor part', 'ccvm', 'value')),
3453     (875, 'fmus', 'k',                  oils_i18n_gettext('875', 'Vocal score', 'ccvm', 'value')),
3454     (876, 'fmus', 'l',                  oils_i18n_gettext('876', 'Score', 'ccvm', 'value')),
3455     (877, 'fmus', 'm',                  oils_i18n_gettext('877', 'Multiple score formats', 'ccvm', 'value')),
3456     (878, 'fmus', 'n',                  oils_i18n_gettext('878', 'Not applicable', 'ccvm', 'value')),
3457     (879, 'fmus', 'u',                  oils_i18n_gettext('879', 'Unknown', 'ccvm', 'value')),
3458     (880, 'fmus', 'z',                  oils_i18n_gettext('880', 'Other', 'ccvm', 'value')),
3459         
3460     (881, 'ltxt', ' ',                  oils_i18n_gettext('881', 'Item is a music sound recording', 'ccvm', 'value')),
3461     (882, 'ltxt', 'a',                  oils_i18n_gettext('882', 'Autobiography', 'ccvm', 'value')),
3462     (883, 'ltxt', 'b',                  oils_i18n_gettext('883', 'Biography', 'ccvm', 'value')),
3463     (884, 'ltxt', 'c',                  oils_i18n_gettext('884', 'Conference proceedings', 'ccvm', 'value')),
3464     (885, 'ltxt', 'd',                  oils_i18n_gettext('885', 'Drama', 'ccvm', 'value')),
3465     (886, 'ltxt', 'e',                  oils_i18n_gettext('886', 'Essays', 'ccvm', 'value')),
3466     (887, 'ltxt', 'f',                  oils_i18n_gettext('887', 'Fiction', 'ccvm', 'value')),
3467     (888, 'ltxt', 'g',                  oils_i18n_gettext('888', 'Reporting', 'ccvm', 'value')),
3468     (889, 'ltxt', 'h',                  oils_i18n_gettext('889', 'History', 'ccvm', 'value')),
3469     (890, 'ltxt', 'i',                  oils_i18n_gettext('890', 'Instruction', 'ccvm', 'value')),
3470     (891, 'ltxt', 'j',                  oils_i18n_gettext('891', 'Language instruction', 'ccvm', 'value')),
3471     (892, 'ltxt', 'k',                  oils_i18n_gettext('892', 'Comedy', 'ccvm', 'value')),
3472     (893, 'ltxt', 'l',                  oils_i18n_gettext('893', 'Lectures, speeches', 'ccvm', 'value')),
3473     (894, 'ltxt', 'm',                  oils_i18n_gettext('894', 'Memoirs', 'ccvm', 'value')),
3474     (895, 'ltxt', 'n',                  oils_i18n_gettext('895', 'Not applicable', 'ccvm', 'value')),
3475     (896, 'ltxt', 'o',                  oils_i18n_gettext('896', 'Folktales', 'ccvm', 'value')),
3476     (897, 'ltxt', 'p',                  oils_i18n_gettext('897', 'Poetry', 'ccvm', 'value')),
3477     (898, 'ltxt', 'r',                  oils_i18n_gettext('898', 'Rehearsals', 'ccvm', 'value')),
3478     (899, 'ltxt', 's',                  oils_i18n_gettext('899', 'Sounds', 'ccvm', 'value')),
3479     (900, 'ltxt', 't',                  oils_i18n_gettext('900', 'Interviews', 'ccvm', 'value')),
3480     (901, 'ltxt', 'z',                  oils_i18n_gettext('901', 'Other', 'ccvm', 'value')),
3481         
3482     (902, 'orig', ' ',                  oils_i18n_gettext('902', 'None of the following', 'ccvm', 'value')),
3483     (903, 'orig', 'a',                  oils_i18n_gettext('903', 'Microfilm', 'ccvm', 'value')),
3484     (904, 'orig', 'b',                  oils_i18n_gettext('904', 'Microfiche', 'ccvm', 'value')),
3485     (905, 'orig', 'c',                  oils_i18n_gettext('905', 'Microopaque', 'ccvm', 'value')),
3486     (906, 'orig', 'd',                  oils_i18n_gettext('906', 'Large print', 'ccvm', 'value')),
3487     (907, 'orig', 'e',                  oils_i18n_gettext('907', 'Newspaper format', 'ccvm', 'value')),
3488     (908, 'orig', 'f',                  oils_i18n_gettext('908', 'Braille', 'ccvm', 'value')),
3489     (909, 'orig', 'o',                  oils_i18n_gettext('909', 'Online', 'ccvm', 'value')),
3490     (910, 'orig', 'q',                  oils_i18n_gettext('910', 'Direct electronic', 'ccvm', 'value')),
3491     (911, 'orig', 's',                  oils_i18n_gettext('911', 'Electronic', 'ccvm', 'value')),
3492         
3493     (912, 'part', ' ',                  oils_i18n_gettext('912', 'No parts in hand or not specified', 'ccvm', 'value')),
3494     (913, 'part', 'd',                  oils_i18n_gettext('913', 'Instrumental and vocal parts', 'ccvm', 'value')),
3495     (914, 'part', 'e',                  oils_i18n_gettext('914', 'Instrumental parts', 'ccvm', 'value')),
3496     (915, 'part', 'f',                  oils_i18n_gettext('915', 'Vocal parts', 'ccvm', 'value')),
3497     (916, 'part', 'n',                  oils_i18n_gettext('916', 'Not Applicable', 'ccvm', 'value')),
3498     (917, 'part', 'u',                  oils_i18n_gettext('917', 'Unknown', 'ccvm', 'value')),
3499         
3500     (918, 'proj', '  ',                 oils_i18n_gettext('918', 'Project not specified', 'ccvm', 'value')),
3501     (919, 'proj', 'aa',                 oils_i18n_gettext('919', 'Aitoff', 'ccvm', 'value')),
3502     (920, 'proj', 'ab',                 oils_i18n_gettext('920', 'Gnomic', 'ccvm', 'value')),
3503     (921, 'proj', 'ac',                 oils_i18n_gettext('921', 'Lambert''s azimuthal equal area', 'ccvm', 'value')),
3504     (922, 'proj', 'ad',                 oils_i18n_gettext('922', 'Orthographic', 'ccvm', 'value')),
3505     (923, 'proj', 'ae',                 oils_i18n_gettext('923', 'Azimuthal equidistant', 'ccvm', 'value')),
3506     (924, 'proj', 'af',                 oils_i18n_gettext('924', 'Stereographic', 'ccvm', 'value')),
3507     (925, 'proj', 'ag',                 oils_i18n_gettext('925', 'General vertical near-sided', 'ccvm', 'value')),
3508     (926, 'proj', 'am',                 oils_i18n_gettext('926', 'Modified stereographic for Alaska', 'ccvm', 'value')),
3509     (927, 'proj', 'an',                 oils_i18n_gettext('927', 'Chamberlin trimetric', 'ccvm', 'value')),
3510     (928, 'proj', 'ap',                 oils_i18n_gettext('928', 'Polar stereographic', 'ccvm', 'value')),
3511     (929, 'proj', 'au',                 oils_i18n_gettext('929', 'Azimuthal, specific type unknown', 'ccvm', 'value')),
3512     (930, 'proj', 'az',                 oils_i18n_gettext('930', 'Azimuthal, other', 'ccvm', 'value')),
3513     (931, 'proj', 'ba',                 oils_i18n_gettext('931', 'Gall', 'ccvm', 'value')),
3514     (932, 'proj', 'bb',                 oils_i18n_gettext('932', 'Goode''s homolographic', 'ccvm', 'value')),
3515     (933, 'proj', 'bc',                 oils_i18n_gettext('933', 'Lambert''s cylindrical equal area', 'ccvm', 'value')),
3516     (934, 'proj', 'bd',                 oils_i18n_gettext('934', 'Mercator', 'ccvm', 'value')),
3517     (935, 'proj', 'be',                 oils_i18n_gettext('935', 'Miller', 'ccvm', 'value')),
3518     (936, 'proj', 'bf',                 oils_i18n_gettext('936', 'Mollweide', 'ccvm', 'value')),
3519     (937, 'proj', 'bg',                 oils_i18n_gettext('937', 'Sinusoidal', 'ccvm', 'value')),
3520     (938, 'proj', 'bh',                 oils_i18n_gettext('938', 'Transverse Mercator', 'ccvm', 'value')),
3521     (939, 'proj', 'bi',                 oils_i18n_gettext('939', 'Gauss-Kruger', 'ccvm', 'value')),
3522     (940, 'proj', 'bj',                 oils_i18n_gettext('940', 'Equirectangular', 'ccvm', 'value')),
3523     (941, 'proj', 'bk',                 oils_i18n_gettext('941', 'Krovak', 'ccvm', 'value')),
3524     (942, 'proj', 'bl',                 oils_i18n_gettext('942', 'Cassini-Soldner', 'ccvm', 'value')),
3525     (943, 'proj', 'bo',                 oils_i18n_gettext('943', 'Oblique Mercator', 'ccvm', 'value')),
3526     (944, 'proj', 'br',                 oils_i18n_gettext('944', 'Robinson', 'ccvm', 'value')),
3527     (945, 'proj', 'bs',                 oils_i18n_gettext('945', 'Space oblique Mercator', 'ccvm', 'value')),
3528     (946, 'proj', 'bu',                 oils_i18n_gettext('946', 'Cylindrical, specific type unknown', 'ccvm', 'value')),
3529     (947, 'proj', 'bz',                 oils_i18n_gettext('947', 'Cylindrical, other', 'ccvm', 'value')),
3530     (948, 'proj', 'ca',                 oils_i18n_gettext('948', 'Alber''s equal area', 'ccvm', 'value')),
3531     (949, 'proj', 'cb',                 oils_i18n_gettext('949', 'Bonne', 'ccvm', 'value')),
3532     (950, 'proj', 'cc',                 oils_i18n_gettext('950', 'Lambert''s conformal conic', 'ccvm', 'value')),
3533     (951, 'proj', 'ce',                 oils_i18n_gettext('951', 'Equidistant conic', 'ccvm', 'value')),
3534     (952, 'proj', 'cp',                 oils_i18n_gettext('952', 'Polyconic', 'ccvm', 'value')),
3535     (953, 'proj', 'cu',                 oils_i18n_gettext('953', 'Conic, specific type unknown', 'ccvm', 'value')),
3536     (954, 'proj', 'cz',                 oils_i18n_gettext('954', 'Conic, other', 'ccvm', 'value')),
3537     (955, 'proj', 'da',                 oils_i18n_gettext('955', 'Armadillo', 'ccvm', 'value')),
3538     (956, 'proj', 'db',                 oils_i18n_gettext('956', 'Butterfly', 'ccvm', 'value')),
3539     (957, 'proj', 'dc',                 oils_i18n_gettext('957', 'Eckert', 'ccvm', 'value')),
3540     (958, 'proj', 'dd',                 oils_i18n_gettext('958', 'Goode''s homolosine', 'ccvm', 'value')),
3541     (959, 'proj', 'de',                 oils_i18n_gettext('959', 'Miller''s bipolar oblique conformal conic', 'ccvm', 'value')),
3542     (960, 'proj', 'df',                 oils_i18n_gettext('960', 'Van Der Grinten', 'ccvm', 'value')),
3543     (961, 'proj', 'dg',                 oils_i18n_gettext('961', 'Dymaxion', 'ccvm', 'value')),
3544     (962, 'proj', 'dh',                 oils_i18n_gettext('962', 'Cordiform', 'ccvm', 'value')),
3545     (963, 'proj', 'dl',                 oils_i18n_gettext('963', 'Lambert conformal', 'ccvm', 'value')),
3546     (964, 'proj', 'zz',                 oils_i18n_gettext('964', 'Other', 'ccvm', 'value')),
3547         
3548     (965, 'relf', ' ',                  oils_i18n_gettext('965', 'No relief shown', 'ccvm', 'value')),
3549     (966, 'relf', 'a',                  oils_i18n_gettext('966', 'Contours', 'ccvm', 'value')),
3550     (967, 'relf', 'b',                  oils_i18n_gettext('967', 'Shading', 'ccvm', 'value')),
3551     (968, 'relf', 'c',                  oils_i18n_gettext('968', 'Gradient and bathymetric tints', 'ccvm', 'value')),
3552     (969, 'relf', 'd',                  oils_i18n_gettext('969', 'Hachures', 'ccvm', 'value')),
3553     (970, 'relf', 'e',                  oils_i18n_gettext('970', 'Bathymetry, soundings', 'ccvm', 'value')),
3554     (971, 'relf', 'f',                  oils_i18n_gettext('971', 'Form lines', 'ccvm', 'value')),
3555     (972, 'relf', 'g',                  oils_i18n_gettext('972', 'Spot heights', 'ccvm', 'value')),
3556     (973, 'relf', 'i',                  oils_i18n_gettext('973', 'Pictorially', 'ccvm', 'value')),
3557     (974, 'relf', 'j',                  oils_i18n_gettext('974', 'Land forms', 'ccvm', 'value')),
3558     (975, 'relf', 'k',                  oils_i18n_gettext('975', 'Bathymetry, isolines', 'ccvm', 'value')),
3559     (976, 'relf', 'm',                  oils_i18n_gettext('976', 'Rock drawings', 'ccvm', 'value')),
3560     (977, 'relf', 'z',                  oils_i18n_gettext('977', 'Other', 'ccvm', 'value')),
3561         
3562     (978, 'spfm', ' ',                  oils_i18n_gettext('978', 'No specified special format characteristics', 'ccvm', 'value')),
3563     (979, 'spfm', 'e',                  oils_i18n_gettext('979', 'Manuscript', 'ccvm', 'value')),
3564     (980, 'spfm', 'j',                  oils_i18n_gettext('980', 'Picture card, post card', 'ccvm', 'value')),
3565     (981, 'spfm', 'k',                  oils_i18n_gettext('981', 'Calendar', 'ccvm', 'value')),
3566     (982, 'spfm', 'l',                  oils_i18n_gettext('982', 'Puzzle', 'ccvm', 'value')),
3567     (983, 'spfm', 'n',                  oils_i18n_gettext('983', 'Game', 'ccvm', 'value')),
3568     (984, 'spfm', 'o',                  oils_i18n_gettext('984', 'Wall map', 'ccvm', 'value')),
3569     (985, 'spfm', 'p',                  oils_i18n_gettext('985', 'Playing cards', 'ccvm', 'value')),
3570     (986, 'spfm', 'r',                  oils_i18n_gettext('986', 'Loose-leaf', 'ccvm', 'value')),
3571     (987, 'spfm', 'z',                  oils_i18n_gettext('987', 'Other', 'ccvm', 'value')),
3572         
3573     (988, 'srtp', ' ',                  oils_i18n_gettext('988', 'None of the following', 'ccvm', 'value')),
3574     (989, 'srtp', 'd',                  oils_i18n_gettext('989', 'Updating database', 'ccvm', 'value')),
3575     (990, 'srtp', 'l',                  oils_i18n_gettext('990', 'Updating loose-leaf', 'ccvm', 'value')),
3576     (991, 'srtp', 'm',                  oils_i18n_gettext('991', 'Monographic series', 'ccvm', 'value')),
3577     (992, 'srtp', 'n',                  oils_i18n_gettext('992', 'Newspaper', 'ccvm', 'value')),
3578     (993, 'srtp', 'p',                  oils_i18n_gettext('993', 'Periodical', 'ccvm', 'value')),
3579     (994, 'srtp', 'w',                  oils_i18n_gettext('994', 'Updating Web site', 'ccvm', 'value')),
3580         
3581     (995, 'tech', 'a',                  oils_i18n_gettext('995', 'Animation', 'ccvm', 'value')),
3582     (996, 'tech', 'c',                  oils_i18n_gettext('996', 'Animation and live action', 'ccvm', 'value')),
3583     (997, 'tech', 'l',                  oils_i18n_gettext('997', 'Live action', 'ccvm', 'value')),
3584     (998, 'tech', 'n',                  oils_i18n_gettext('998', 'Not applicable', 'ccvm', 'value')),
3585     (999, 'tech', 'u',                  oils_i18n_gettext('999', 'Unknown', 'ccvm', 'value')),
3586     (1000, 'tech', 'z',                 oils_i18n_gettext('1000', 'Other', 'ccvm', 'value')),
3587         
3588     (1001, 'trar', ' ',                 oils_i18n_gettext('1001', 'Not arrangement or transposition or not specified', 'ccvm', 'value')),
3589     (1002, 'trar', 'a',                 oils_i18n_gettext('1002', 'Transposition', 'ccvm', 'value')),
3590     (1003, 'trar', 'b',                 oils_i18n_gettext('1003', 'Arrangement', 'ccvm', 'value')),
3591     (1004, 'trar', 'c',                 oils_i18n_gettext('1004', 'Both transposed and arranged', 'ccvm', 'value')),
3592     (1005, 'trar', 'n',                 oils_i18n_gettext('1005', 'Not applicable', 'ccvm', 'value')),
3593     (1006, 'trar', 'u',                 oils_i18n_gettext('1006', 'Unknown', 'ccvm', 'value')),
3594         
3595     (1007, 'ctry', 'aa ',               oils_i18n_gettext('1007', 'Albania ', 'ccvm', 'value')),
3596     (1008, 'ctry', 'abc',               oils_i18n_gettext('1008', 'Alberta ', 'ccvm', 'value')),
3597     (1009, 'ctry', 'aca',               oils_i18n_gettext('1009', 'Australian Capital Territory ', 'ccvm', 'value')),
3598     (1010, 'ctry', 'ae ',               oils_i18n_gettext('1010', 'Algeria ', 'ccvm', 'value')),
3599     (1011, 'ctry', 'af ',               oils_i18n_gettext('1011', 'Afghanistan ', 'ccvm', 'value')),
3600     (1012, 'ctry', 'ag ',               oils_i18n_gettext('1012', 'Argentina ', 'ccvm', 'value')),
3601     (1013, 'ctry', 'ai ',               oils_i18n_gettext('1013', 'Armenia (Republic) ', 'ccvm', 'value')),
3602     (1014, 'ctry', 'aj ',               oils_i18n_gettext('1014', 'Azerbaijan ', 'ccvm', 'value')),
3603     (1015, 'ctry', 'aku',               oils_i18n_gettext('1015', 'Alaska ', 'ccvm', 'value')),
3604     (1016, 'ctry', 'alu',               oils_i18n_gettext('1016', 'Alabama ', 'ccvm', 'value')),
3605     (1017, 'ctry', 'am ',               oils_i18n_gettext('1017', 'Anguilla ', 'ccvm', 'value')),
3606     (1018, 'ctry', 'an ',               oils_i18n_gettext('1018', 'Andorra ', 'ccvm', 'value')),
3607     (1019, 'ctry', 'ao ',               oils_i18n_gettext('1019', 'Angola ', 'ccvm', 'value')),
3608     (1020, 'ctry', 'aq ',               oils_i18n_gettext('1020', 'Antigua and Barbuda ', 'ccvm', 'value')),
3609     (1021, 'ctry', 'aru',               oils_i18n_gettext('1021', 'Arkansas ', 'ccvm', 'value')),
3610     (1022, 'ctry', 'as ',               oils_i18n_gettext('1022', 'American Samoa ', 'ccvm', 'value')),
3611     (1023, 'ctry', 'at ',               oils_i18n_gettext('1023', 'Australia ', 'ccvm', 'value')),
3612     (1024, 'ctry', 'au ',               oils_i18n_gettext('1024', 'Austria ', 'ccvm', 'value')),
3613     (1025, 'ctry', 'aw ',               oils_i18n_gettext('1025', 'Aruba ', 'ccvm', 'value')),
3614     (1026, 'ctry', 'ay ',               oils_i18n_gettext('1026', 'Antarctica ', 'ccvm', 'value')),
3615     (1027, 'ctry', 'azu',               oils_i18n_gettext('1027', 'Arizona ', 'ccvm', 'value')),
3616     (1028, 'ctry', 'ba ',               oils_i18n_gettext('1028', 'Bahrain ', 'ccvm', 'value')),
3617     (1029, 'ctry', 'bb ',               oils_i18n_gettext('1029', 'Barbados ', 'ccvm', 'value')),
3618     (1030, 'ctry', 'bcc',               oils_i18n_gettext('1030', 'British Columbia ', 'ccvm', 'value')),
3619     (1031, 'ctry', 'bd ',               oils_i18n_gettext('1031', 'Burundi ', 'ccvm', 'value')),
3620     (1032, 'ctry', 'be ',               oils_i18n_gettext('1032', 'Belgium ', 'ccvm', 'value')),
3621     (1033, 'ctry', 'bf ',               oils_i18n_gettext('1033', 'Bahamas ', 'ccvm', 'value')),
3622     (1034, 'ctry', 'bg ',               oils_i18n_gettext('1034', 'Bangladesh ', 'ccvm', 'value')),
3623     (1035, 'ctry', 'bh ',               oils_i18n_gettext('1035', 'Belize ', 'ccvm', 'value')),
3624     (1036, 'ctry', 'bi ',               oils_i18n_gettext('1036', 'British Indian Ocean Territory ', 'ccvm', 'value')),
3625     (1037, 'ctry', 'bl ',               oils_i18n_gettext('1037', 'Brazil ', 'ccvm', 'value')),
3626     (1038, 'ctry', 'bm ',               oils_i18n_gettext('1038', 'Bermuda Islands ', 'ccvm', 'value')),
3627     (1039, 'ctry', 'bn ',               oils_i18n_gettext('1039', 'Bosnia and Herzegovina ', 'ccvm', 'value')),
3628     (1040, 'ctry', 'bo ',               oils_i18n_gettext('1040', 'Bolivia ', 'ccvm', 'value')),
3629     (1041, 'ctry', 'bp ',               oils_i18n_gettext('1041', 'Solomon Islands ', 'ccvm', 'value')),
3630     (1042, 'ctry', 'br ',               oils_i18n_gettext('1042', 'Burma ', 'ccvm', 'value')),
3631     (1043, 'ctry', 'bs ',               oils_i18n_gettext('1043', 'Botswana ', 'ccvm', 'value')),
3632     (1044, 'ctry', 'bt ',               oils_i18n_gettext('1044', 'Bhutan ', 'ccvm', 'value')),
3633     (1045, 'ctry', 'bu ',               oils_i18n_gettext('1045', 'Bulgaria ', 'ccvm', 'value')),
3634     (1046, 'ctry', 'bv ',               oils_i18n_gettext('1046', 'Bouvet Island ', 'ccvm', 'value')),
3635     (1047, 'ctry', 'bw ',               oils_i18n_gettext('1047', 'Belarus ', 'ccvm', 'value')),
3636     (1048, 'ctry', 'bx ',               oils_i18n_gettext('1048', 'Brunei ', 'ccvm', 'value')),
3637     (1049, 'ctry', 'ca ',               oils_i18n_gettext('1049', 'Caribbean Netherlands ', 'ccvm', 'value')),
3638     (1050, 'ctry', 'cau',               oils_i18n_gettext('1050', 'California ', 'ccvm', 'value')),
3639     (1051, 'ctry', 'cb ',               oils_i18n_gettext('1051', 'Cambodia ', 'ccvm', 'value')),
3640     (1052, 'ctry', 'cc ',               oils_i18n_gettext('1052', 'China ', 'ccvm', 'value')),
3641     (1053, 'ctry', 'cd ',               oils_i18n_gettext('1053', 'Chad ', 'ccvm', 'value')),
3642     (1054, 'ctry', 'ce ',               oils_i18n_gettext('1054', 'Sri Lanka ', 'ccvm', 'value')),
3643     (1055, 'ctry', 'cf ',               oils_i18n_gettext('1055', 'Congo (Brazzaville) ', 'ccvm', 'value')),
3644     (1056, 'ctry', 'cg ',               oils_i18n_gettext('1056', 'Congo (Democratic Republic) ', 'ccvm', 'value')),
3645     (1057, 'ctry', 'ch ',               oils_i18n_gettext('1057', 'China (Republic : 1949', 'ccvm', 'value')),
3646     (1058, 'ctry', 'ci ',               oils_i18n_gettext('1058', 'Croatia ', 'ccvm', 'value')),
3647     (1059, 'ctry', 'cj ',               oils_i18n_gettext('1059', 'Cayman Islands ', 'ccvm', 'value')),
3648     (1060, 'ctry', 'ck ',               oils_i18n_gettext('1060', 'Colombia ', 'ccvm', 'value')),
3649     (1061, 'ctry', 'cl ',               oils_i18n_gettext('1061', 'Chile ', 'ccvm', 'value')),
3650     (1062, 'ctry', 'cm ',               oils_i18n_gettext('1062', 'Cameroon ', 'ccvm', 'value')),
3651     (1063, 'ctry', 'co ',               oils_i18n_gettext('1063', 'Curaçao ', 'ccvm', 'value')),
3652     (1064, 'ctry', 'cou',               oils_i18n_gettext('1064', 'Colorado ', 'ccvm', 'value')),
3653     (1065, 'ctry', 'cq ',               oils_i18n_gettext('1065', 'Comoros ', 'ccvm', 'value')),
3654     (1066, 'ctry', 'cr ',               oils_i18n_gettext('1066', 'Costa Rica ', 'ccvm', 'value')),
3655     (1067, 'ctry', 'ctu',               oils_i18n_gettext('1067', 'Connecticut ', 'ccvm', 'value')),
3656     (1068, 'ctry', 'cu ',               oils_i18n_gettext('1068', 'Cuba ', 'ccvm', 'value')),
3657     (1069, 'ctry', 'cv ',               oils_i18n_gettext('1069', 'Cabo Verde ', 'ccvm', 'value')),
3658     (1070, 'ctry', 'cw ',               oils_i18n_gettext('1070', 'Cook Islands ', 'ccvm', 'value')),
3659     (1071, 'ctry', 'cx ',               oils_i18n_gettext('1071', 'Central African Republic ', 'ccvm', 'value')),
3660     (1072, 'ctry', 'cy ',               oils_i18n_gettext('1072', 'Cyprus ', 'ccvm', 'value')),
3661     (1073, 'ctry', 'dcu',               oils_i18n_gettext('1073', 'District of Columbia ', 'ccvm', 'value')),
3662     (1074, 'ctry', 'deu',               oils_i18n_gettext('1074', 'Delaware ', 'ccvm', 'value')),
3663     (1075, 'ctry', 'dk ',               oils_i18n_gettext('1075', 'Denmark ', 'ccvm', 'value')),
3664     (1076, 'ctry', 'dm ',               oils_i18n_gettext('1076', 'Benin ', 'ccvm', 'value')),
3665     (1077, 'ctry', 'dq ',               oils_i18n_gettext('1077', 'Dominica ', 'ccvm', 'value')),
3666     (1078, 'ctry', 'dr ',               oils_i18n_gettext('1078', 'Dominican Republic ', 'ccvm', 'value')),
3667     (1079, 'ctry', 'ea ',               oils_i18n_gettext('1079', 'Eritrea ', 'ccvm', 'value')),
3668     (1080, 'ctry', 'ec ',               oils_i18n_gettext('1080', 'Ecuador ', 'ccvm', 'value')),
3669     (1081, 'ctry', 'eg ',               oils_i18n_gettext('1081', 'Equatorial Guinea ', 'ccvm', 'value')),
3670     (1082, 'ctry', 'em ',               oils_i18n_gettext('1082', 'Timor', 'ccvm', 'value')),
3671     (1083, 'ctry', 'enk',               oils_i18n_gettext('1083', 'England ', 'ccvm', 'value')),
3672     (1084, 'ctry', 'er ',               oils_i18n_gettext('1084', 'Estonia ', 'ccvm', 'value')),
3673     (1085, 'ctry', 'es ',               oils_i18n_gettext('1085', 'El Salvador ', 'ccvm', 'value')),
3674     (1086, 'ctry', 'et ',               oils_i18n_gettext('1086', 'Ethiopia ', 'ccvm', 'value')),
3675     (1087, 'ctry', 'fa ',               oils_i18n_gettext('1087', 'Faroe Islands ', 'ccvm', 'value')),
3676     (1088, 'ctry', 'fg ',               oils_i18n_gettext('1088', 'French Guiana ', 'ccvm', 'value')),
3677     (1089, 'ctry', 'fi ',               oils_i18n_gettext('1089', 'Finland ', 'ccvm', 'value')),
3678     (1090, 'ctry', 'fj ',               oils_i18n_gettext('1090', 'Fiji ', 'ccvm', 'value')),
3679     (1091, 'ctry', 'fk ',               oils_i18n_gettext('1091', 'Falkland Islands ', 'ccvm', 'value')),
3680     (1092, 'ctry', 'flu',               oils_i18n_gettext('1092', 'Florida ', 'ccvm', 'value')),
3681     (1093, 'ctry', 'fm ',               oils_i18n_gettext('1093', 'Micronesia (Federated States) ', 'ccvm', 'value')),
3682     (1094, 'ctry', 'fp ',               oils_i18n_gettext('1094', 'French Polynesia ', 'ccvm', 'value')),
3683     (1095, 'ctry', 'fr ',               oils_i18n_gettext('1095', 'France ', 'ccvm', 'value')),
3684     (1096, 'ctry', 'fs ',               oils_i18n_gettext('1096', 'Terres australes et antarctiques françaises ', 'ccvm', 'value')),
3685     (1097, 'ctry', 'ft ',               oils_i18n_gettext('1097', 'Djibouti ', 'ccvm', 'value')),
3686     (1098, 'ctry', 'gau',               oils_i18n_gettext('1098', 'Georgia ', 'ccvm', 'value')),
3687     (1099, 'ctry', 'gb ',               oils_i18n_gettext('1099', 'Kiribati ', 'ccvm', 'value')),
3688     (1100, 'ctry', 'gd ',               oils_i18n_gettext('1100', 'Grenada ', 'ccvm', 'value')),
3689     (1101, 'ctry', 'gh ',               oils_i18n_gettext('1101', 'Ghana ', 'ccvm', 'value')),
3690     (1102, 'ctry', 'gi ',               oils_i18n_gettext('1102', 'Gibraltar ', 'ccvm', 'value')),
3691     (1103, 'ctry', 'gl ',               oils_i18n_gettext('1103', 'Greenland ', 'ccvm', 'value')),
3692     (1104, 'ctry', 'gm ',               oils_i18n_gettext('1104', 'Gambia ', 'ccvm', 'value')),
3693     (1105, 'ctry', 'go ',               oils_i18n_gettext('1105', 'Gabon ', 'ccvm', 'value')),
3694     (1106, 'ctry', 'gp ',               oils_i18n_gettext('1106', 'Guadeloupe ', 'ccvm', 'value')),
3695     (1107, 'ctry', 'gr ',               oils_i18n_gettext('1107', 'Greece ', 'ccvm', 'value')),
3696     (1108, 'ctry', 'gs ',               oils_i18n_gettext('1108', 'Georgia (Republic) ', 'ccvm', 'value')),
3697     (1109, 'ctry', 'gt ',               oils_i18n_gettext('1109', 'Guatemala ', 'ccvm', 'value')),
3698     (1110, 'ctry', 'gu ',               oils_i18n_gettext('1110', 'Guam ', 'ccvm', 'value')),
3699     (1111, 'ctry', 'gv ',               oils_i18n_gettext('1111', 'Guinea ', 'ccvm', 'value')),
3700     (1112, 'ctry', 'gw ',               oils_i18n_gettext('1112', 'Germany ', 'ccvm', 'value')),
3701     (1113, 'ctry', 'gy ',               oils_i18n_gettext('1113', 'Guyana ', 'ccvm', 'value')),
3702     (1114, 'ctry', 'gz ',               oils_i18n_gettext('1114', 'Gaza Strip ', 'ccvm', 'value')),
3703     (1115, 'ctry', 'hiu',               oils_i18n_gettext('1115', 'Hawaii ', 'ccvm', 'value')),
3704     (1116, 'ctry', 'hm ',               oils_i18n_gettext('1116', 'Heard and McDonald Islands ', 'ccvm', 'value')),
3705     (1117, 'ctry', 'ho ',               oils_i18n_gettext('1117', 'Honduras ', 'ccvm', 'value')),
3706     (1118, 'ctry', 'ht ',               oils_i18n_gettext('1118', 'Haiti ', 'ccvm', 'value')),
3707     (1119, 'ctry', 'hu ',               oils_i18n_gettext('1119', 'Hungary ', 'ccvm', 'value')),
3708     (1120, 'ctry', 'iau',               oils_i18n_gettext('1120', 'Iowa ', 'ccvm', 'value')),
3709     (1121, 'ctry', 'ic ',               oils_i18n_gettext('1121', 'Iceland ', 'ccvm', 'value')),
3710     (1122, 'ctry', 'idu',               oils_i18n_gettext('1122', 'Idaho ', 'ccvm', 'value')),
3711     (1123, 'ctry', 'ie ',               oils_i18n_gettext('1123', 'Ireland ', 'ccvm', 'value')),
3712     (1124, 'ctry', 'ii ',               oils_i18n_gettext('1124', 'India ', 'ccvm', 'value')),
3713     (1125, 'ctry', 'ilu',               oils_i18n_gettext('1125', 'Illinois ', 'ccvm', 'value')),
3714     (1126, 'ctry', 'inu',               oils_i18n_gettext('1126', 'Indiana ', 'ccvm', 'value')),
3715     (1127, 'ctry', 'io ',               oils_i18n_gettext('1127', 'Indonesia ', 'ccvm', 'value')),
3716     (1128, 'ctry', 'iq ',               oils_i18n_gettext('1128', 'Iraq ', 'ccvm', 'value')),
3717     (1129, 'ctry', 'ir ',               oils_i18n_gettext('1129', 'Iran ', 'ccvm', 'value')),
3718     (1130, 'ctry', 'is ',               oils_i18n_gettext('1130', 'Israel ', 'ccvm', 'value')),
3719     (1131, 'ctry', 'it ',               oils_i18n_gettext('1131', 'Italy ', 'ccvm', 'value')),
3720     (1132, 'ctry', 'iv ',               oils_i18n_gettext('1132', 'Côte d''Ivoire ', 'ccvm', 'value')),
3721     (1133, 'ctry', 'iy ',               oils_i18n_gettext('1133', 'Iraq', 'ccvm', 'value')),
3722     (1134, 'ctry', 'ja ',               oils_i18n_gettext('1134', 'Japan ', 'ccvm', 'value')),
3723     (1135, 'ctry', 'ji ',               oils_i18n_gettext('1135', 'Johnston Atoll ', 'ccvm', 'value')),
3724     (1136, 'ctry', 'jm ',               oils_i18n_gettext('1136', 'Jamaica ', 'ccvm', 'value')),
3725     (1137, 'ctry', 'jo ',               oils_i18n_gettext('1137', 'Jordan ', 'ccvm', 'value')),
3726     (1138, 'ctry', 'ke ',               oils_i18n_gettext('1138', 'Kenya ', 'ccvm', 'value')),
3727     (1139, 'ctry', 'kg ',               oils_i18n_gettext('1139', 'Kyrgyzstan ', 'ccvm', 'value')),
3728     (1140, 'ctry', 'kn ',               oils_i18n_gettext('1140', 'Korea (North) ', 'ccvm', 'value')),
3729     (1141, 'ctry', 'ko ',               oils_i18n_gettext('1141', 'Korea (South) ', 'ccvm', 'value')),
3730     (1142, 'ctry', 'ksu',               oils_i18n_gettext('1142', 'Kansas ', 'ccvm', 'value')),
3731     (1143, 'ctry', 'ku ',               oils_i18n_gettext('1143', 'Kuwait ', 'ccvm', 'value')),
3732     (1144, 'ctry', 'kv ',               oils_i18n_gettext('1144', 'Kosovo ', 'ccvm', 'value')),
3733     (1145, 'ctry', 'kyu',               oils_i18n_gettext('1145', 'Kentucky ', 'ccvm', 'value')),
3734     (1146, 'ctry', 'kz ',               oils_i18n_gettext('1146', 'Kazakhstan ', 'ccvm', 'value')),
3735     (1147, 'ctry', 'lau',               oils_i18n_gettext('1147', 'Louisiana ', 'ccvm', 'value')),
3736     (1148, 'ctry', 'lb ',               oils_i18n_gettext('1148', 'Liberia ', 'ccvm', 'value')),
3737     (1149, 'ctry', 'le ',               oils_i18n_gettext('1149', 'Lebanon ', 'ccvm', 'value')),
3738     (1150, 'ctry', 'lh ',               oils_i18n_gettext('1150', 'Liechtenstein ', 'ccvm', 'value')),
3739     (1151, 'ctry', 'li ',               oils_i18n_gettext('1151', 'Lithuania ', 'ccvm', 'value')),
3740     (1152, 'ctry', 'lo ',               oils_i18n_gettext('1152', 'Lesotho ', 'ccvm', 'value')),
3741     (1153, 'ctry', 'ls ',               oils_i18n_gettext('1153', 'Laos ', 'ccvm', 'value')),
3742     (1154, 'ctry', 'lu ',               oils_i18n_gettext('1154', 'Luxembourg ', 'ccvm', 'value')),
3743     (1155, 'ctry', 'lv ',               oils_i18n_gettext('1155', 'Latvia ', 'ccvm', 'value')),
3744     (1156, 'ctry', 'ly ',               oils_i18n_gettext('1156', 'Libya ', 'ccvm', 'value')),
3745     (1157, 'ctry', 'mau',               oils_i18n_gettext('1157', 'Massachusetts ', 'ccvm', 'value')),
3746     (1158, 'ctry', 'mbc',               oils_i18n_gettext('1158', 'Manitoba ', 'ccvm', 'value')),
3747     (1159, 'ctry', 'mc ',               oils_i18n_gettext('1159', 'Monaco ', 'ccvm', 'value')),
3748     (1160, 'ctry', 'mdu',               oils_i18n_gettext('1160', 'Maryland ', 'ccvm', 'value')),
3749     (1161, 'ctry', 'meu',               oils_i18n_gettext('1161', 'Maine ', 'ccvm', 'value')),
3750     (1162, 'ctry', 'mf ',               oils_i18n_gettext('1162', 'Mauritius ', 'ccvm', 'value')),
3751     (1163, 'ctry', 'mg ',               oils_i18n_gettext('1163', 'Madagascar ', 'ccvm', 'value')),
3752     (1164, 'ctry', 'miu',               oils_i18n_gettext('1164', 'Michigan ', 'ccvm', 'value')),
3753     (1165, 'ctry', 'mj ',               oils_i18n_gettext('1165', 'Montserrat ', 'ccvm', 'value')),
3754     (1166, 'ctry', 'mk ',               oils_i18n_gettext('1166', 'Oman ', 'ccvm', 'value')),
3755     (1167, 'ctry', 'ml ',               oils_i18n_gettext('1167', 'Mali ', 'ccvm', 'value')),
3756     (1168, 'ctry', 'mm ',               oils_i18n_gettext('1168', 'Malta ', 'ccvm', 'value')),
3757     (1169, 'ctry', 'mnu',               oils_i18n_gettext('1169', 'Minnesota ', 'ccvm', 'value')),
3758     (1170, 'ctry', 'mo ',               oils_i18n_gettext('1170', 'Montenegro ', 'ccvm', 'value')),
3759     (1171, 'ctry', 'mou',               oils_i18n_gettext('1171', 'Missouri ', 'ccvm', 'value')),
3760     (1172, 'ctry', 'mp ',               oils_i18n_gettext('1172', 'Mongolia ', 'ccvm', 'value')),
3761     (1173, 'ctry', 'mq ',               oils_i18n_gettext('1173', 'Martinique ', 'ccvm', 'value')),
3762     (1174, 'ctry', 'mr ',               oils_i18n_gettext('1174', 'Morocco ', 'ccvm', 'value')),
3763     (1175, 'ctry', 'msu',               oils_i18n_gettext('1175', 'Mississippi ', 'ccvm', 'value')),
3764     (1176, 'ctry', 'mtu',               oils_i18n_gettext('1176', 'Montana ', 'ccvm', 'value')),
3765     (1177, 'ctry', 'mu ',               oils_i18n_gettext('1177', 'Mauritania ', 'ccvm', 'value')),
3766     (1178, 'ctry', 'mv ',               oils_i18n_gettext('1178', 'Moldova ', 'ccvm', 'value')),
3767     (1179, 'ctry', 'mw ',               oils_i18n_gettext('1179', 'Malawi ', 'ccvm', 'value')),
3768     (1180, 'ctry', 'mx ',               oils_i18n_gettext('1180', 'Mexico ', 'ccvm', 'value')),
3769     (1181, 'ctry', 'my ',               oils_i18n_gettext('1181', 'Malaysia ', 'ccvm', 'value')),
3770     (1182, 'ctry', 'mz ',               oils_i18n_gettext('1182', 'Mozambique ', 'ccvm', 'value')),
3771     (1183, 'ctry', 'nbu',               oils_i18n_gettext('1183', 'Nebraska ', 'ccvm', 'value')),
3772     (1184, 'ctry', 'ncu',               oils_i18n_gettext('1184', 'North Carolina ', 'ccvm', 'value')),
3773     (1185, 'ctry', 'ndu',               oils_i18n_gettext('1185', 'North Dakota ', 'ccvm', 'value')),
3774     (1186, 'ctry', 'ne ',               oils_i18n_gettext('1186', 'Netherlands ', 'ccvm', 'value')),
3775     (1187, 'ctry', 'nfc',               oils_i18n_gettext('1187', 'Newfoundland and Labrador ', 'ccvm', 'value')),
3776     (1188, 'ctry', 'ng ',               oils_i18n_gettext('1188', 'Niger ', 'ccvm', 'value')),
3777     (1189, 'ctry', 'nhu',               oils_i18n_gettext('1189', 'New Hampshire ', 'ccvm', 'value')),
3778     (1190, 'ctry', 'nik',               oils_i18n_gettext('1190', 'Northern Ireland ', 'ccvm', 'value')),
3779     (1191, 'ctry', 'nju',               oils_i18n_gettext('1191', 'New Jersey ', 'ccvm', 'value')),
3780     (1192, 'ctry', 'nkc',               oils_i18n_gettext('1192', 'New Brunswick ', 'ccvm', 'value')),
3781     (1193, 'ctry', 'nl ',               oils_i18n_gettext('1193', 'New Caledonia ', 'ccvm', 'value')),
3782     (1194, 'ctry', 'nmu',               oils_i18n_gettext('1194', 'New Mexico ', 'ccvm', 'value')),
3783     (1195, 'ctry', 'nn ',               oils_i18n_gettext('1195', 'Vanuatu ', 'ccvm', 'value')),
3784     (1196, 'ctry', 'no ',               oils_i18n_gettext('1196', 'Norway ', 'ccvm', 'value')),
3785     (1197, 'ctry', 'np ',               oils_i18n_gettext('1197', 'Nepal ', 'ccvm', 'value')),
3786     (1198, 'ctry', 'nq ',               oils_i18n_gettext('1198', 'Nicaragua ', 'ccvm', 'value')),
3787     (1199, 'ctry', 'nr ',               oils_i18n_gettext('1199', 'Nigeria ', 'ccvm', 'value')),
3788     (1200, 'ctry', 'nsc',               oils_i18n_gettext('1200', 'Nova Scotia ', 'ccvm', 'value')),
3789     (1201, 'ctry', 'ntc',               oils_i18n_gettext('1201', 'Northwest Territories ', 'ccvm', 'value')),
3790     (1202, 'ctry', 'nu ',               oils_i18n_gettext('1202', 'Nauru ', 'ccvm', 'value')),
3791     (1203, 'ctry', 'nuc',               oils_i18n_gettext('1203', 'Nunavut ', 'ccvm', 'value')),
3792     (1204, 'ctry', 'nvu',               oils_i18n_gettext('1204', 'Nevada ', 'ccvm', 'value')),
3793     (1205, 'ctry', 'nw ',               oils_i18n_gettext('1205', 'Northern Mariana Islands ', 'ccvm', 'value')),
3794     (1206, 'ctry', 'nx ',               oils_i18n_gettext('1206', 'Norfolk Island ', 'ccvm', 'value')),
3795     (1207, 'ctry', 'nyu',               oils_i18n_gettext('1207', 'New York (State) ', 'ccvm', 'value')),
3796     (1208, 'ctry', 'nz ',               oils_i18n_gettext('1208', 'New Zealand ', 'ccvm', 'value')),
3797     (1209, 'ctry', 'ohu',               oils_i18n_gettext('1209', 'Ohio ', 'ccvm', 'value')),
3798     (1210, 'ctry', 'oku',               oils_i18n_gettext('1210', 'Oklahoma ', 'ccvm', 'value')),
3799     (1211, 'ctry', 'onc',               oils_i18n_gettext('1211', 'Ontario ', 'ccvm', 'value')),
3800     (1212, 'ctry', 'oru',               oils_i18n_gettext('1212', 'Oregon ', 'ccvm', 'value')),
3801     (1213, 'ctry', 'ot ',               oils_i18n_gettext('1213', 'Mayotte ', 'ccvm', 'value')),
3802     (1214, 'ctry', 'pau',               oils_i18n_gettext('1214', 'Pennsylvania ', 'ccvm', 'value')),
3803     (1215, 'ctry', 'pc ',               oils_i18n_gettext('1215', 'Pitcairn Island ', 'ccvm', 'value')),
3804     (1216, 'ctry', 'pe ',               oils_i18n_gettext('1216', 'Peru ', 'ccvm', 'value')),
3805     (1217, 'ctry', 'pf ',               oils_i18n_gettext('1217', 'Paracel Islands ', 'ccvm', 'value')),
3806     (1218, 'ctry', 'pg ',               oils_i18n_gettext('1218', 'Guinea', 'ccvm', 'value')),
3807     (1219, 'ctry', 'ph ',               oils_i18n_gettext('1219', 'Philippines ', 'ccvm', 'value')),
3808     (1220, 'ctry', 'pic',               oils_i18n_gettext('1220', 'Prince Edward Island ', 'ccvm', 'value')),
3809     (1221, 'ctry', 'pk ',               oils_i18n_gettext('1221', 'Pakistan ', 'ccvm', 'value')),
3810     (1222, 'ctry', 'pl ',               oils_i18n_gettext('1222', 'Poland ', 'ccvm', 'value')),
3811     (1223, 'ctry', 'pn ',               oils_i18n_gettext('1223', 'Panama ', 'ccvm', 'value')),
3812     (1224, 'ctry', 'po ',               oils_i18n_gettext('1224', 'Portugal ', 'ccvm', 'value')),
3813     (1225, 'ctry', 'pp ',               oils_i18n_gettext('1225', 'Papua New Guinea ', 'ccvm', 'value')),
3814     (1226, 'ctry', 'pr ',               oils_i18n_gettext('1226', 'Puerto Rico ', 'ccvm', 'value')),
3815     (1227, 'ctry', 'pw ',               oils_i18n_gettext('1227', 'Palau ', 'ccvm', 'value')),
3816     (1228, 'ctry', 'py ',               oils_i18n_gettext('1228', 'Paraguay ', 'ccvm', 'value')),
3817     (1229, 'ctry', 'qa ',               oils_i18n_gettext('1229', 'Qatar ', 'ccvm', 'value')),
3818     (1230, 'ctry', 'qea',               oils_i18n_gettext('1230', 'Queensland ', 'ccvm', 'value')),
3819     (1231, 'ctry', 'quc',               oils_i18n_gettext('1231', 'Québec (Province) ', 'ccvm', 'value')),
3820     (1232, 'ctry', 'rb ',               oils_i18n_gettext('1232', 'Serbia ', 'ccvm', 'value')),
3821     (1233, 'ctry', 're ',               oils_i18n_gettext('1233', 'Réunion ', 'ccvm', 'value')),
3822     (1234, 'ctry', 'rh ',               oils_i18n_gettext('1234', 'Zimbabwe ', 'ccvm', 'value')),
3823     (1235, 'ctry', 'riu',               oils_i18n_gettext('1235', 'Rhode Island ', 'ccvm', 'value')),
3824     (1236, 'ctry', 'rm ',               oils_i18n_gettext('1236', 'Romania ', 'ccvm', 'value')),
3825     (1237, 'ctry', 'ru ',               oils_i18n_gettext('1237', 'Russia (Federation) ', 'ccvm', 'value')),
3826     (1238, 'ctry', 'rw ',               oils_i18n_gettext('1238', 'Rwanda ', 'ccvm', 'value')),
3827     (1239, 'ctry', 'sa ',               oils_i18n_gettext('1239', 'South Africa ', 'ccvm', 'value')),
3828     (1240, 'ctry', 'sc ',               oils_i18n_gettext('1240', 'Saint', 'ccvm', 'value')),
3829     (1241, 'ctry', 'scu',               oils_i18n_gettext('1241', 'South Carolina ', 'ccvm', 'value')),
3830     (1242, 'ctry', 'sd ',               oils_i18n_gettext('1242', 'South Sudan ', 'ccvm', 'value')),
3831     (1243, 'ctry', 'sdu',               oils_i18n_gettext('1243', 'South Dakota ', 'ccvm', 'value')),
3832     (1244, 'ctry', 'se ',               oils_i18n_gettext('1244', 'Seychelles ', 'ccvm', 'value')),
3833     (1245, 'ctry', 'sf ',               oils_i18n_gettext('1245', 'Sao Tome and Principe ', 'ccvm', 'value')),
3834     (1246, 'ctry', 'sg ',               oils_i18n_gettext('1246', 'Senegal ', 'ccvm', 'value')),
3835     (1247, 'ctry', 'sh ',               oils_i18n_gettext('1247', 'Spanish North Africa ', 'ccvm', 'value')),
3836     (1248, 'ctry', 'si ',               oils_i18n_gettext('1248', 'Singapore ', 'ccvm', 'value')),
3837     (1249, 'ctry', 'sj ',               oils_i18n_gettext('1249', 'Sudan ', 'ccvm', 'value')),
3838     (1250, 'ctry', 'sl ',               oils_i18n_gettext('1250', 'Sierra Leone ', 'ccvm', 'value')),
3839     (1251, 'ctry', 'sm ',               oils_i18n_gettext('1251', 'San Marino ', 'ccvm', 'value')),
3840     (1252, 'ctry', 'sn ',               oils_i18n_gettext('1252', 'Sint Maarten ', 'ccvm', 'value')),
3841     (1253, 'ctry', 'snc',               oils_i18n_gettext('1253', 'Saskatchewan ', 'ccvm', 'value')),
3842     (1254, 'ctry', 'so ',               oils_i18n_gettext('1254', 'Somalia ', 'ccvm', 'value')),
3843     (1255, 'ctry', 'sp ',               oils_i18n_gettext('1255', 'Spain ', 'ccvm', 'value')),
3844     (1256, 'ctry', 'sq ',               oils_i18n_gettext('1256', 'Swaziland ', 'ccvm', 'value')),
3845     (1257, 'ctry', 'sr ',               oils_i18n_gettext('1257', 'Surinam ', 'ccvm', 'value')),
3846     (1258, 'ctry', 'ss ',               oils_i18n_gettext('1258', 'Western Sahara ', 'ccvm', 'value')),
3847     (1259, 'ctry', 'st ',               oils_i18n_gettext('1259', 'Saint', 'ccvm', 'value')),
3848     (1260, 'ctry', 'stk',               oils_i18n_gettext('1260', 'Scotland ', 'ccvm', 'value')),
3849     (1261, 'ctry', 'su ',               oils_i18n_gettext('1261', 'Saudi Arabia ', 'ccvm', 'value')),
3850     (1262, 'ctry', 'sw ',               oils_i18n_gettext('1262', 'Sweden ', 'ccvm', 'value')),
3851     (1263, 'ctry', 'sx ',               oils_i18n_gettext('1263', 'Namibia ', 'ccvm', 'value')),
3852     (1264, 'ctry', 'sy ',               oils_i18n_gettext('1264', 'Syria ', 'ccvm', 'value')),
3853     (1265, 'ctry', 'sz ',               oils_i18n_gettext('1265', 'Switzerland ', 'ccvm', 'value')),
3854     (1266, 'ctry', 'ta ',               oils_i18n_gettext('1266', 'Tajikistan ', 'ccvm', 'value')),
3855     (1267, 'ctry', 'tc ',               oils_i18n_gettext('1267', 'Turks and Caicos Islands ', 'ccvm', 'value')),
3856     (1268, 'ctry', 'tg ',               oils_i18n_gettext('1268', 'Togo ', 'ccvm', 'value')),
3857     (1269, 'ctry', 'th ',               oils_i18n_gettext('1269', 'Thailand ', 'ccvm', 'value')),
3858     (1270, 'ctry', 'ti ',               oils_i18n_gettext('1270', 'Tunisia ', 'ccvm', 'value')),
3859     (1271, 'ctry', 'tk ',               oils_i18n_gettext('1271', 'Turkmenistan ', 'ccvm', 'value')),
3860     (1272, 'ctry', 'tl ',               oils_i18n_gettext('1272', 'Tokelau ', 'ccvm', 'value')),
3861     (1273, 'ctry', 'tma',               oils_i18n_gettext('1273', 'Tasmania ', 'ccvm', 'value')),
3862     (1274, 'ctry', 'tnu',               oils_i18n_gettext('1274', 'Tennessee ', 'ccvm', 'value')),
3863     (1275, 'ctry', 'to ',               oils_i18n_gettext('1275', 'Tonga ', 'ccvm', 'value')),
3864     (1276, 'ctry', 'tr ',               oils_i18n_gettext('1276', 'Trinidad and Tobago ', 'ccvm', 'value')),
3865     (1277, 'ctry', 'ts ',               oils_i18n_gettext('1277', 'United Arab Emirates ', 'ccvm', 'value')),
3866     (1278, 'ctry', 'tu ',               oils_i18n_gettext('1278', 'Turkey ', 'ccvm', 'value')),
3867     (1279, 'ctry', 'tv ',               oils_i18n_gettext('1279', 'Tuvalu ', 'ccvm', 'value')),
3868     (1280, 'ctry', 'txu',               oils_i18n_gettext('1280', 'Texas ', 'ccvm', 'value')),
3869     (1281, 'ctry', 'tz ',               oils_i18n_gettext('1281', 'Tanzania ', 'ccvm', 'value')),
3870     (1282, 'ctry', 'ua ',               oils_i18n_gettext('1282', 'Egypt ', 'ccvm', 'value')),
3871     (1283, 'ctry', 'uc ',               oils_i18n_gettext('1283', 'United States Misc. Caribbean Islands ', 'ccvm', 'value')),
3872     (1284, 'ctry', 'ug ',               oils_i18n_gettext('1284', 'Uganda ', 'ccvm', 'value')),
3873     (1285, 'ctry', 'uik',               oils_i18n_gettext('1285', 'United Kingdom Misc. Islands ', 'ccvm', 'value')),
3874     (1286, 'ctry', 'un ',               oils_i18n_gettext('1286', 'Ukraine ', 'ccvm', 'value')),
3875     (1287, 'ctry', 'up ',               oils_i18n_gettext('1287', 'United States Misc. Pacific Islands ', 'ccvm', 'value')),
3876     (1288, 'ctry', 'utu',               oils_i18n_gettext('1288', 'Utah ', 'ccvm', 'value')),
3877     (1289, 'ctry', 'uv ',               oils_i18n_gettext('1289', 'Burkina Faso ', 'ccvm', 'value')),
3878     (1290, 'ctry', 'uy ',               oils_i18n_gettext('1290', 'Uruguay ', 'ccvm', 'value')),
3879     (1291, 'ctry', 'uz ',               oils_i18n_gettext('1291', 'Uzbekistan ', 'ccvm', 'value')),
3880     (1292, 'ctry', 'vau',               oils_i18n_gettext('1292', 'Virginia ', 'ccvm', 'value')),
3881     (1293, 'ctry', 'vb ',               oils_i18n_gettext('1293', 'British Virgin Islands ', 'ccvm', 'value')),
3882     (1294, 'ctry', 'vc ',               oils_i18n_gettext('1294', 'Vatican City ', 'ccvm', 'value')),
3883     (1295, 'ctry', 've ',               oils_i18n_gettext('1295', 'Venezuela ', 'ccvm', 'value')),
3884     (1296, 'ctry', 'vi ',               oils_i18n_gettext('1296', 'Virgin Islands of the United States ', 'ccvm', 'value')),
3885     (1297, 'ctry', 'vm ',               oils_i18n_gettext('1297', 'Vietnam ', 'ccvm', 'value')),
3886     (1298, 'ctry', 'vp ',               oils_i18n_gettext('1298', 'Various places ', 'ccvm', 'value')),
3887     (1299, 'ctry', 'vra',               oils_i18n_gettext('1299', 'Victoria ', 'ccvm', 'value')),
3888     (1300, 'ctry', 'vtu',               oils_i18n_gettext('1300', 'Vermont ', 'ccvm', 'value')),
3889     (1301, 'ctry', 'wau',               oils_i18n_gettext('1301', 'Washington (State) ', 'ccvm', 'value')),
3890     (1302, 'ctry', 'wea',               oils_i18n_gettext('1302', 'Western Australia ', 'ccvm', 'value')),
3891     (1303, 'ctry', 'wf ',               oils_i18n_gettext('1303', 'Wallis and Futuna ', 'ccvm', 'value')),
3892     (1304, 'ctry', 'wiu',               oils_i18n_gettext('1304', 'Wisconsin ', 'ccvm', 'value')),
3893     (1305, 'ctry', 'wj ',               oils_i18n_gettext('1305', 'West Bank of the Jordan River ', 'ccvm', 'value')),
3894     (1306, 'ctry', 'wk ',               oils_i18n_gettext('1306', 'Wake Island ', 'ccvm', 'value')),
3895     (1307, 'ctry', 'wlk',               oils_i18n_gettext('1307', 'Wales ', 'ccvm', 'value')),
3896     (1308, 'ctry', 'ws ',               oils_i18n_gettext('1308', 'Samoa ', 'ccvm', 'value')),
3897     (1309, 'ctry', 'wvu',               oils_i18n_gettext('1309', 'West Virginia ', 'ccvm', 'value')),
3898     (1310, 'ctry', 'wyu',               oils_i18n_gettext('1310', 'Wyoming ', 'ccvm', 'value')),
3899     (1311, 'ctry', 'xa ',               oils_i18n_gettext('1311', 'Christmas Island (Indian Ocean) ', 'ccvm', 'value')),
3900     (1312, 'ctry', 'xb ',               oils_i18n_gettext('1312', 'Cocos (Keeling) Islands ', 'ccvm', 'value')),
3901     (1313, 'ctry', 'xc ',               oils_i18n_gettext('1313', 'Maldives ', 'ccvm', 'value')),
3902     (1314, 'ctry', 'xd ',               oils_i18n_gettext('1314', 'Saint Kitts', 'ccvm', 'value')),
3903     (1315, 'ctry', 'xe ',               oils_i18n_gettext('1315', 'Marshall Islands ', 'ccvm', 'value')),
3904     (1316, 'ctry', 'xf ',               oils_i18n_gettext('1316', 'Midway Islands ', 'ccvm', 'value')),
3905     (1317, 'ctry', 'xga',               oils_i18n_gettext('1317', 'Coral Sea Islands Territory ', 'ccvm', 'value')),
3906     (1318, 'ctry', 'xh ',               oils_i18n_gettext('1318', 'Niue ', 'ccvm', 'value')),
3907     (1319, 'ctry', 'xj ',               oils_i18n_gettext('1319', 'Saint Helena ', 'ccvm', 'value')),
3908     (1320, 'ctry', 'xk ',               oils_i18n_gettext('1320', 'Saint Lucia ', 'ccvm', 'value')),
3909     (1321, 'ctry', 'xl ',               oils_i18n_gettext('1321', 'Saint Pierre and Miquelon ', 'ccvm', 'value')),
3910     (1322, 'ctry', 'xm ',               oils_i18n_gettext('1322', 'Saint Vincent and the Grenadines ', 'ccvm', 'value')),
3911     (1323, 'ctry', 'xn ',               oils_i18n_gettext('1323', 'Macedonia ', 'ccvm', 'value')),
3912     (1324, 'ctry', 'xna',               oils_i18n_gettext('1324', 'New South Wales ', 'ccvm', 'value')),
3913     (1325, 'ctry', 'xo ',               oils_i18n_gettext('1325', 'Slovakia ', 'ccvm', 'value')),
3914     (1326, 'ctry', 'xoa',               oils_i18n_gettext('1326', 'Northern Territory ', 'ccvm', 'value')),
3915     (1327, 'ctry', 'xp ',               oils_i18n_gettext('1327', 'Spratly Island ', 'ccvm', 'value')),
3916     (1328, 'ctry', 'xr ',               oils_i18n_gettext('1328', 'Czech Republic ', 'ccvm', 'value')),
3917     (1329, 'ctry', 'xra',               oils_i18n_gettext('1329', 'South Australia ', 'ccvm', 'value')),
3918     (1330, 'ctry', 'xs ',               oils_i18n_gettext('1330', 'South Georgia and the South Sandwich Islands ', 'ccvm', 'value')),
3919     (1331, 'ctry', 'xv ',               oils_i18n_gettext('1331', 'Slovenia ', 'ccvm', 'value')),
3920     (1332, 'ctry', 'xx ',               oils_i18n_gettext('1332', 'No place, unknown, or undetermined ', 'ccvm', 'value')),
3921     (1333, 'ctry', 'xxc',               oils_i18n_gettext('1333', 'Canada ', 'ccvm', 'value')),
3922     (1334, 'ctry', 'xxk',               oils_i18n_gettext('1334', 'United Kingdom ', 'ccvm', 'value')),
3923     (1335, 'ctry', 'xxu',               oils_i18n_gettext('1335', 'United States ', 'ccvm', 'value')),
3924     (1336, 'ctry', 'ye ',               oils_i18n_gettext('1336', 'Yemen ', 'ccvm', 'value')),
3925     (1337, 'ctry', 'ykc',               oils_i18n_gettext('1337', 'Yukon Territory ', 'ccvm', 'value')),
3926     (1338, 'ctry', 'za ',               oils_i18n_gettext('1338', 'Zambia ', 'ccvm', 'value')),
3927         
3928     (1339, 'pub_status', 'b',   oils_i18n_gettext('1339', 'No dates given; B.C. date involved', 'ccvm', 'value')),
3929     (1340, 'pub_status', 'c',   oils_i18n_gettext('1340', 'Continuing resource currently published', 'ccvm', 'value')),
3930     (1341, 'pub_status', 'd',   oils_i18n_gettext('1341', 'Continuing resource ceased publication', 'ccvm', 'value')),
3931     (1342, 'pub_status', 'e',   oils_i18n_gettext('1342', 'Detailed date', 'ccvm', 'value')),
3932     (1343, 'pub_status', 'i',   oils_i18n_gettext('1343', 'Inclusive dates of collection', 'ccvm', 'value')),
3933     (1344, 'pub_status', 'k',   oils_i18n_gettext('1344', 'Range of years of bulk of collection', 'ccvm', 'value')),
3934     (1345, 'pub_status', 'm',   oils_i18n_gettext('1345', 'Multiple dates', 'ccvm', 'value')),
3935     (1346, 'pub_status', 'n',   oils_i18n_gettext('1346', 'Dates unknown', 'ccvm', 'value')),
3936     (1347, 'pub_status', 'p',   oils_i18n_gettext('1347', 'Date of distribution/release/issue and production/recording session when different', 'ccvm', 'value')),
3937     (1348, 'pub_status', 'q',   oils_i18n_gettext('1348', 'Questionable date', 'ccvm', 'value')),
3938     (1349, 'pub_status', 'r',   oils_i18n_gettext('1349', 'Reprint/reissue date and original date', 'ccvm', 'value')),
3939     (1350, 'pub_status', 's',   oils_i18n_gettext('1350', 'Single known date/probable date', 'ccvm', 'value')),
3940     (1351, 'pub_status', 't',   oils_i18n_gettext('1351', 'Publication date and copyright date', 'ccvm', 'value')),
3941     (1352, 'pub_status', 'u',   oils_i18n_gettext('1352', 'Continuing resource status unknown', 'ccvm', 'value'));
3942         
3943
3944 -- These are fixed fields that are made up of multiple single-character codes. These are the actual fields that are used to define relevent attributes,
3945 -- the "unnumbered" version of these fields are used for the MARC editor and as composite attributes for use in the OPAC if desired.
3946 -- i18n ids are left as-is because there's no need to have multiple translations for the same value.
3947 -- The ' ' codes only apply to the first position because if there's anything in pos 1 then the rest of the spaces are just filler.
3948 -- There's also no need for them to be opac visible because there will be composite attributes that OR these numbered attributes together.
3949 INSERT INTO config.coded_value_map (id, ctype, code, value, opac_visible) VALUES
3950     (1353, 'accm1', ' ',        oils_i18n_gettext('1735', 'No accompanying matter', 'ccvm', 'value'), FALSE),
3951     (1354, 'accm1', 'a',        oils_i18n_gettext('713', 'Discography', 'ccvm', 'value'), FALSE),
3952     (1355, 'accm1', 'b',        oils_i18n_gettext('714', 'Bibliography', 'ccvm', 'value'), FALSE),
3953     (1356, 'accm1', 'c',        oils_i18n_gettext('715', 'Thematic index', 'ccvm', 'value'), FALSE),
3954     (1357, 'accm1', 'd',        oils_i18n_gettext('716', 'Libretto or text', 'ccvm', 'value'), FALSE),
3955     (1358, 'accm1', 'e',        oils_i18n_gettext('717', 'Biography of composer or author', 'ccvm', 'value'), FALSE),
3956     (1359, 'accm1', 'f',        oils_i18n_gettext('718', 'Biography or performer or history of ensemble', 'ccvm', 'value'), FALSE),
3957     (1360, 'accm1', 'g',        oils_i18n_gettext('719', 'Technical and/or historical information on instruments', 'ccvm', 'value'), FALSE),
3958     (1361, 'accm1', 'h',        oils_i18n_gettext('720', 'Technical information on music', 'ccvm', 'value'), FALSE),
3959     (1362, 'accm1', 'i',        oils_i18n_gettext('721', 'Historical information', 'ccvm', 'value'), FALSE),
3960     (1363, 'accm1', 'k',        oils_i18n_gettext('722', 'Ethnological information', 'ccvm', 'value'), FALSE),
3961     (1364, 'accm1', 'r',        oils_i18n_gettext('723', 'Instructional materials', 'ccvm', 'value'), FALSE),
3962     (1365, 'accm1', 's',        oils_i18n_gettext('724', 'Music', 'ccvm', 'value'), FALSE),
3963     (1366, 'accm1', 'z',        oils_i18n_gettext('725', 'Other accompanying matter', 'ccvm', 'value'), FALSE),
3964         
3965     (1367, 'accm2', 'a',        oils_i18n_gettext('713', 'Discography', 'ccvm', 'value'), FALSE),
3966     (1368, 'accm2', 'b',        oils_i18n_gettext('714', 'Bibliography', 'ccvm', 'value'), FALSE),
3967     (1369, 'accm2', 'c',        oils_i18n_gettext('715', 'Thematic index', 'ccvm', 'value'), FALSE),
3968     (1370, 'accm2', 'd',        oils_i18n_gettext('716', 'Libretto or text', 'ccvm', 'value'), FALSE),
3969     (1371, 'accm2', 'e',        oils_i18n_gettext('717', 'Biography of composer or author', 'ccvm', 'value'), FALSE),
3970     (1372, 'accm2', 'f',        oils_i18n_gettext('718', 'Biography or performer or history of ensemble', 'ccvm', 'value'), FALSE),
3971     (1373, 'accm2', 'g',        oils_i18n_gettext('719', 'Technical and/or historical information on instruments', 'ccvm', 'value'), FALSE),
3972     (1374, 'accm2', 'h',        oils_i18n_gettext('720', 'Technical information on music', 'ccvm', 'value'), FALSE),
3973     (1375, 'accm2', 'i',        oils_i18n_gettext('721', 'Historical information', 'ccvm', 'value'), FALSE),
3974     (1376, 'accm2', 'k',        oils_i18n_gettext('722', 'Ethnological information', 'ccvm', 'value'), FALSE),
3975     (1377, 'accm2', 'r',        oils_i18n_gettext('723', 'Instructional materials', 'ccvm', 'value'), FALSE),
3976     (1378, 'accm2', 's',        oils_i18n_gettext('724', 'Music', 'ccvm', 'value'), FALSE),
3977     (1379, 'accm2', 'z',        oils_i18n_gettext('725', 'Other accompanying matter', 'ccvm', 'value'), FALSE),
3978         
3979     (1380, 'accm3', 'a',        oils_i18n_gettext('713', 'Discography', 'ccvm', 'value'), FALSE),
3980     (1381, 'accm3', 'b',        oils_i18n_gettext('714', 'Bibliography', 'ccvm', 'value'), FALSE),
3981     (1382, 'accm3', 'c',        oils_i18n_gettext('715', 'Thematic index', 'ccvm', 'value'), FALSE),
3982     (1383, 'accm3', 'd',        oils_i18n_gettext('716', 'Libretto or text', 'ccvm', 'value'), FALSE),
3983     (1384, 'accm3', 'e',        oils_i18n_gettext('717', 'Biography of composer or author', 'ccvm', 'value'), FALSE),
3984     (1385, 'accm3', 'f',        oils_i18n_gettext('718', 'Biography or performer or history of ensemble', 'ccvm', 'value'), FALSE),
3985     (1386, 'accm3', 'g',        oils_i18n_gettext('719', 'Technical and/or historical information on instruments', 'ccvm', 'value'), FALSE),
3986     (1387, 'accm3', 'h',        oils_i18n_gettext('720', 'Technical information on music', 'ccvm', 'value'), FALSE),
3987     (1388, 'accm3', 'i',        oils_i18n_gettext('721', 'Historical information', 'ccvm', 'value'), FALSE),
3988     (1389, 'accm3', 'k',        oils_i18n_gettext('722', 'Ethnological information', 'ccvm', 'value'), FALSE),
3989     (1390, 'accm3', 'r',        oils_i18n_gettext('723', 'Instructional materials', 'ccvm', 'value'), FALSE),
3990     (1391, 'accm3', 's',        oils_i18n_gettext('724', 'Music', 'ccvm', 'value'), FALSE),
3991     (1392, 'accm3', 'z',        oils_i18n_gettext('725', 'Other accompanying matter', 'ccvm', 'value'), FALSE),
3992         
3993     (1393, 'accm4', 'a',        oils_i18n_gettext('713', 'Discography', 'ccvm', 'value'), FALSE),
3994     (1394, 'accm4', 'b',        oils_i18n_gettext('714', 'Bibliography', 'ccvm', 'value'), FALSE),
3995     (1395, 'accm4', 'c',        oils_i18n_gettext('715', 'Thematic index', 'ccvm', 'value'), FALSE),
3996     (1396, 'accm4', 'd',        oils_i18n_gettext('716', 'Libretto or text', 'ccvm', 'value'), FALSE),
3997     (1397, 'accm4', 'e',        oils_i18n_gettext('717', 'Biography of composer or author', 'ccvm', 'value'), FALSE),
3998     (1398, 'accm4', 'f',        oils_i18n_gettext('718', 'Biography or performer or history of ensemble', 'ccvm', 'value'), FALSE),
3999     (1399, 'accm4', 'g',        oils_i18n_gettext('719', 'Technical and/or historical information on instruments', 'ccvm', 'value'), FALSE),
4000     (1400, 'accm4', 'h',        oils_i18n_gettext('720', 'Technical information on music', 'ccvm', 'value'), FALSE),
4001     (1401, 'accm4', 'i',        oils_i18n_gettext('721', 'Historical information', 'ccvm', 'value'), FALSE),
4002     (1402, 'accm4', 'k',        oils_i18n_gettext('722', 'Ethnological information', 'ccvm', 'value'), FALSE),
4003     (1403, 'accm4', 'r',        oils_i18n_gettext('723', 'Instructional materials', 'ccvm', 'value'), FALSE),
4004     (1404, 'accm4', 's',        oils_i18n_gettext('724', 'Music', 'ccvm', 'value'), FALSE),
4005     (1405, 'accm4', 'z',        oils_i18n_gettext('725', 'Other accompanying matter', 'ccvm', 'value'), FALSE),
4006         
4007     (1406, 'accm5', 'a',        oils_i18n_gettext('713', 'Discography', 'ccvm', 'value'), FALSE),
4008     (1407, 'accm5', 'b',        oils_i18n_gettext('714', 'Bibliography', 'ccvm', 'value'), FALSE),
4009     (1408, 'accm5', 'c',        oils_i18n_gettext('715', 'Thematic index', 'ccvm', 'value'), FALSE),
4010     (1409, 'accm5', 'd',        oils_i18n_gettext('716', 'Libretto or text', 'ccvm', 'value'), FALSE),
4011     (1410, 'accm5', 'e',        oils_i18n_gettext('717', 'Biography of composer or author', 'ccvm', 'value'), FALSE),
4012     (1411, 'accm5', 'f',        oils_i18n_gettext('718', 'Biography or performer or history of ensemble', 'ccvm', 'value'), FALSE),
4013     (1412, 'accm5', 'g',        oils_i18n_gettext('719', 'Technical and/or historical information on instruments', 'ccvm', 'value'), FALSE),
4014     (1413, 'accm5', 'h',        oils_i18n_gettext('720', 'Technical information on music', 'ccvm', 'value'), FALSE),
4015     (1414, 'accm5', 'i',        oils_i18n_gettext('721', 'Historical information', 'ccvm', 'value'), FALSE),
4016     (1415, 'accm5', 'k',        oils_i18n_gettext('722', 'Ethnological information', 'ccvm', 'value'), FALSE),
4017     (1416, 'accm5', 'r',        oils_i18n_gettext('723', 'Instructional materials', 'ccvm', 'value'), FALSE),
4018     (1417, 'accm5', 's',        oils_i18n_gettext('724', 'Music', 'ccvm', 'value'), FALSE),
4019     (1418, 'accm5', 'z',        oils_i18n_gettext('725', 'Other accompanying matter', 'ccvm', 'value'), FALSE),
4020         
4021     (1419, 'accm6', 'a',        oils_i18n_gettext('713', 'Discography', 'ccvm', 'value'), FALSE),
4022     (1420, 'accm6', 'b',        oils_i18n_gettext('714', 'Bibliography', 'ccvm', 'value'), FALSE),
4023     (1421, 'accm6', 'c',        oils_i18n_gettext('715', 'Thematic index', 'ccvm', 'value'), FALSE),
4024     (1422, 'accm6', 'd',        oils_i18n_gettext('716', 'Libretto or text', 'ccvm', 'value'), FALSE),
4025     (1423, 'accm6', 'e',        oils_i18n_gettext('717', 'Biography of composer or author', 'ccvm', 'value'), FALSE),
4026     (1424, 'accm6', 'f',        oils_i18n_gettext('718', 'Biography or performer or history of ensemble', 'ccvm', 'value'), FALSE),
4027     (1425, 'accm6', 'g',        oils_i18n_gettext('719', 'Technical and/or historical information on instruments', 'ccvm', 'value'), FALSE),
4028     (1426, 'accm6', 'h',        oils_i18n_gettext('720', 'Technical information on music', 'ccvm', 'value'), FALSE),
4029     (1427, 'accm6', 'i',        oils_i18n_gettext('721', 'Historical information', 'ccvm', 'value'), FALSE),
4030     (1428, 'accm6', 'k',        oils_i18n_gettext('722', 'Ethnological information', 'ccvm', 'value'), FALSE),
4031     (1429, 'accm6', 'r',        oils_i18n_gettext('723', 'Instructional materials', 'ccvm', 'value'), FALSE),
4032     (1430, 'accm6', 's',        oils_i18n_gettext('724', 'Music', 'ccvm', 'value'), FALSE),
4033     (1431, 'accm6', 'z',        oils_i18n_gettext('725', 'Other accompanying matter', 'ccvm', 'value'), FALSE),
4034         
4035     (1432, 'cont1', ' ',        oils_i18n_gettext('835', 'Not specified', 'ccvm', 'value'), FALSE),
4036     (1433, 'cont1', 'a',        oils_i18n_gettext('836', 'Abstracts/summaries', 'ccvm', 'value'), FALSE),
4037     (1434, 'cont1', 'b',        oils_i18n_gettext('837', 'Bibliographies', 'ccvm', 'value'), FALSE),
4038     (1435, 'cont1', 'c',        oils_i18n_gettext('838', 'Catalogs', 'ccvm', 'value'), FALSE),
4039     (1436, 'cont1', 'd',        oils_i18n_gettext('839', 'Dictionaries', 'ccvm', 'value'), FALSE),
4040     (1437, 'cont1', 'e',        oils_i18n_gettext('840', 'Encyclopedias', 'ccvm', 'value'), FALSE),
4041     (1438, 'cont1', 'f',        oils_i18n_gettext('841', 'Handbooks', 'ccvm', 'value'), FALSE),
4042     (1439, 'cont1', 'g',        oils_i18n_gettext('842', 'Legal articles', 'ccvm', 'value'), FALSE),
4043     (1440, 'cont1', 'h',        oils_i18n_gettext('843', 'Biography', 'ccvm', 'value'), FALSE),
4044     (1441, 'cont1', 'i',        oils_i18n_gettext('844', 'Indexes', 'ccvm', 'value'), FALSE),
4045     (1442, 'cont1', 'j',        oils_i18n_gettext('845', 'Patent document', 'ccvm', 'value'), FALSE),
4046     (1443, 'cont1', 'k',        oils_i18n_gettext('846', 'Discographies', 'ccvm', 'value'), FALSE),
4047     (1444, 'cont1', 'l',        oils_i18n_gettext('847', 'Legislation', 'ccvm', 'value'), FALSE),
4048     (1445, 'cont1', 'm',        oils_i18n_gettext('848', 'Theses', 'ccvm', 'value'), FALSE),
4049     (1446, 'cont1', 'n',        oils_i18n_gettext('849', 'Surveys of the literature in a subject area', 'ccvm', 'value'), FALSE),
4050     (1447, 'cont1', 'o',        oils_i18n_gettext('850', 'Reviews', 'ccvm', 'value'), FALSE),
4051     (1448, 'cont1', 'p',        oils_i18n_gettext('851', 'Programmed texts', 'ccvm', 'value'), FALSE),
4052     (1449, 'cont1', 'q',        oils_i18n_gettext('852', 'Filmographies', 'ccvm', 'value'), FALSE),
4053     (1450, 'cont1', 'r',        oils_i18n_gettext('853', 'Directories', 'ccvm', 'value'), FALSE),
4054     (1451, 'cont1', 's',        oils_i18n_gettext('854', 'Statistics', 'ccvm', 'value'), FALSE),
4055     (1452, 'cont1', 't',        oils_i18n_gettext('855', 'Technical reports', 'ccvm', 'value'), FALSE),
4056     (1453, 'cont1', 'u',        oils_i18n_gettext('856', 'Standards/specifications', 'ccvm', 'value'), FALSE),
4057     (1454, 'cont1', 'v',        oils_i18n_gettext('857', 'Legal cases and case notes', 'ccvm', 'value'), FALSE),
4058     (1455, 'cont1', 'w',        oils_i18n_gettext('858', 'Law reports and digests', 'ccvm', 'value'), FALSE),
4059     (1456, 'cont1', 'x',        oils_i18n_gettext('859', 'Other reports', 'ccvm', 'value'), FALSE),
4060     (1457, 'cont1', 'y',        oils_i18n_gettext('860', 'Yearbooks', 'ccvm', 'value'), FALSE),
4061     (1458, 'cont1', 'z',        oils_i18n_gettext('861', 'Treaties', 'ccvm', 'value'), FALSE),
4062     (1459, 'cont1', '2',        oils_i18n_gettext('862', 'Offprints', 'ccvm', 'value'), FALSE),
4063     (1460, 'cont1', '5',        oils_i18n_gettext('863', 'Calendars', 'ccvm', 'value'), FALSE),
4064     (1461, 'cont1', '6',        oils_i18n_gettext('864', 'Comics/graphic novels', 'ccvm', 'value'), FALSE),
4065         
4066     (1462, 'cont2', 'a',        oils_i18n_gettext('836', 'Abstracts/summaries', 'ccvm', 'value'), FALSE),
4067     (1463, 'cont2', 'b',        oils_i18n_gettext('837', 'Bibliographies', 'ccvm', 'value'), FALSE),
4068     (1464, 'cont2', 'c',        oils_i18n_gettext('838', 'Catalogs', 'ccvm', 'value'), FALSE),
4069     (1465, 'cont2', 'd',        oils_i18n_gettext('839', 'Dictionaries', 'ccvm', 'value'), FALSE),
4070     (1466, 'cont2', 'e',        oils_i18n_gettext('840', 'Encyclopedias', 'ccvm', 'value'), FALSE),
4071     (1467, 'cont2', 'f',        oils_i18n_gettext('841', 'Handbooks', 'ccvm', 'value'), FALSE),
4072     (1468, 'cont2', 'g',        oils_i18n_gettext('842', 'Legal articles', 'ccvm', 'value'), FALSE),
4073     (1469, 'cont2', 'h',        oils_i18n_gettext('843', 'Biography', 'ccvm', 'value'), FALSE),
4074     (1470, 'cont2', 'i',        oils_i18n_gettext('844', 'Indexes', 'ccvm', 'value'), FALSE),
4075     (1471, 'cont2', 'j',        oils_i18n_gettext('845', 'Patent document', 'ccvm', 'value'), FALSE),
4076     (1472, 'cont2', 'k',        oils_i18n_gettext('846', 'Discographies', 'ccvm', 'value'), FALSE),
4077     (1473, 'cont2', 'l',        oils_i18n_gettext('847', 'Legislation', 'ccvm', 'value'), FALSE),
4078     (1474, 'cont2', 'm',        oils_i18n_gettext('848', 'Theses', 'ccvm', 'value'), FALSE),
4079     (1475, 'cont2', 'n',        oils_i18n_gettext('849', 'Surveys of the literature in a subject area', 'ccvm', 'value'), FALSE),
4080     (1476, 'cont2', 'o',        oils_i18n_gettext('850', 'Reviews', 'ccvm', 'value'), FALSE),
4081     (1477, 'cont2', 'p',        oils_i18n_gettext('851', 'Programmed texts', 'ccvm', 'value'), FALSE),
4082     (1478, 'cont2', 'q',        oils_i18n_gettext('852', 'Filmographies', 'ccvm', 'value'), FALSE),
4083     (1479, 'cont2', 'r',        oils_i18n_gettext('853', 'Directories', 'ccvm', 'value'), FALSE),
4084     (1480, 'cont2', 's',        oils_i18n_gettext('854', 'Statistics', 'ccvm', 'value'), FALSE),
4085     (1481, 'cont2', 't',        oils_i18n_gettext('855', 'Technical reports', 'ccvm', 'value'), FALSE),
4086     (1482, 'cont2', 'u',        oils_i18n_gettext('856', 'Standards/specifications', 'ccvm', 'value'), FALSE),
4087     (1483, 'cont2', 'v',        oils_i18n_gettext('857', 'Legal cases and case notes', 'ccvm', 'value'), FALSE),
4088     (1484, 'cont2', 'w',        oils_i18n_gettext('858', 'Law reports and digests', 'ccvm', 'value'), FALSE),
4089     (1485, 'cont2', 'x',        oils_i18n_gettext('859', 'Other reports', 'ccvm', 'value'), FALSE),
4090     (1486, 'cont2', 'y',        oils_i18n_gettext('860', 'Yearbooks', 'ccvm', 'value'), FALSE),
4091     (1487, 'cont2', 'z',        oils_i18n_gettext('861', 'Treaties', 'ccvm', 'value'), FALSE),
4092     (1488, 'cont2', '2',        oils_i18n_gettext('862', 'Offprints', 'ccvm', 'value'), FALSE),
4093     (1489, 'cont2', '5',        oils_i18n_gettext('863', 'Calendars', 'ccvm', 'value'), FALSE),
4094     (1490, 'cont2', '6',        oils_i18n_gettext('864', 'Comics/graphic novels', 'ccvm', 'value'), FALSE),
4095         
4096     (1491, 'cont3', 'a',        oils_i18n_gettext('836', 'Abstracts/summaries', 'ccvm', 'value'), FALSE),
4097     (1492, 'cont3', 'b',        oils_i18n_gettext('837', 'Bibliographies', 'ccvm', 'value'), FALSE),
4098     (1493, 'cont3', 'c',        oils_i18n_gettext('838', 'Catalogs', 'ccvm', 'value'), FALSE),
4099     (1494, 'cont3', 'd',        oils_i18n_gettext('839', 'Dictionaries', 'ccvm', 'value'), FALSE),
4100     (1495, 'cont3', 'e',        oils_i18n_gettext('840', 'Encyclopedias', 'ccvm', 'value'), FALSE),
4101     (1496, 'cont3', 'f',        oils_i18n_gettext('841', 'Handbooks', 'ccvm', 'value'), FALSE),
4102     (1497, 'cont3', 'g',        oils_i18n_gettext('842', 'Legal articles', 'ccvm', 'value'), FALSE),
4103     (1498, 'cont3', 'h',        oils_i18n_gettext('843', 'Biography', 'ccvm', 'value'), FALSE),
4104     (1499, 'cont3', 'i',        oils_i18n_gettext('844', 'Indexes', 'ccvm', 'value'), FALSE),
4105     (1500, 'cont3', 'j',        oils_i18n_gettext('845', 'Patent document', 'ccvm', 'value'), FALSE),
4106     (1501, 'cont3', 'k',        oils_i18n_gettext('846', 'Discographies', 'ccvm', 'value'), FALSE),
4107     (1502, 'cont3', 'l',        oils_i18n_gettext('847', 'Legislation', 'ccvm', 'value'), FALSE),
4108     (1503, 'cont3', 'm',        oils_i18n_gettext('848', 'Theses', 'ccvm', 'value'), FALSE),
4109     (1504, 'cont3', 'n',        oils_i18n_gettext('849', 'Surveys of the literature in a subject area', 'ccvm', 'value'), FALSE),
4110     (1505, 'cont3', 'o',        oils_i18n_gettext('850', 'Reviews', 'ccvm', 'value'), FALSE),
4111     (1506, 'cont3', 'p',        oils_i18n_gettext('851', 'Programmed texts', 'ccvm', 'value'), FALSE),
4112     (1507, 'cont3', 'q',        oils_i18n_gettext('852', 'Filmographies', 'ccvm', 'value'), FALSE),
4113     (1508, 'cont3', 'r',        oils_i18n_gettext('853', 'Directories', 'ccvm', 'value'), FALSE),
4114     (1509, 'cont3', 's',        oils_i18n_gettext('854', 'Statistics', 'ccvm', 'value'), FALSE),
4115     (1510, 'cont3', 't',        oils_i18n_gettext('855', 'Technical reports', 'ccvm', 'value'), FALSE),
4116     (1511, 'cont3', 'u',        oils_i18n_gettext('856', 'Standards/specifications', 'ccvm', 'value'), FALSE),
4117     (1512, 'cont3', 'v',        oils_i18n_gettext('857', 'Legal cases and case notes', 'ccvm', 'value'), FALSE),
4118     (1513, 'cont3', 'w',        oils_i18n_gettext('858', 'Law reports and digests', 'ccvm', 'value'), FALSE),
4119     (1514, 'cont3', 'x',        oils_i18n_gettext('859', 'Other reports', 'ccvm', 'value'), FALSE),
4120     (1515, 'cont3', 'y',        oils_i18n_gettext('860', 'Yearbooks', 'ccvm', 'value'), FALSE),
4121     (1516, 'cont3', 'z',        oils_i18n_gettext('861', 'Treaties', 'ccvm', 'value'), FALSE),
4122     (1517, 'cont3', '2',        oils_i18n_gettext('862', 'Offprints', 'ccvm', 'value'), FALSE),
4123     (1518, 'cont3', '5',        oils_i18n_gettext('863', 'Calendars', 'ccvm', 'value'), FALSE),
4124     (1519, 'cont3', '6',        oils_i18n_gettext('864', 'Comics/graphic novels', 'ccvm', 'value'), FALSE),
4125         
4126     (1520, 'cont4', 'a',        oils_i18n_gettext('836', 'Abstracts/summaries', 'ccvm', 'value'), FALSE),
4127     (1521, 'cont4', 'b',        oils_i18n_gettext('837', 'Bibliographies', 'ccvm', 'value'), FALSE),
4128     (1522, 'cont4', 'c',        oils_i18n_gettext('838', 'Catalogs', 'ccvm', 'value'), FALSE),
4129     (1523, 'cont4', 'd',        oils_i18n_gettext('839', 'Dictionaries', 'ccvm', 'value'), FALSE),
4130     (1524, 'cont4', 'e',        oils_i18n_gettext('840', 'Encyclopedias', 'ccvm', 'value'), FALSE),
4131     (1525, 'cont4', 'f',        oils_i18n_gettext('841', 'Handbooks', 'ccvm', 'value'), FALSE),
4132     (1526, 'cont4', 'g',        oils_i18n_gettext('842', 'Legal articles', 'ccvm', 'value'), FALSE),
4133     (1527, 'cont4', 'h',        oils_i18n_gettext('843', 'Biography', 'ccvm', 'value'), FALSE),
4134     (1528, 'cont4', 'i',        oils_i18n_gettext('844', 'Indexes', 'ccvm', 'value'), FALSE),
4135     (1529, 'cont4', 'j',        oils_i18n_gettext('845', 'Patent document', 'ccvm', 'value'), FALSE),
4136     (1530, 'cont4', 'k',        oils_i18n_gettext('846', 'Discographies', 'ccvm', 'value'), FALSE),
4137     (1531, 'cont4', 'l',        oils_i18n_gettext('847', 'Legislation', 'ccvm', 'value'), FALSE),
4138     (1532, 'cont4', 'm',        oils_i18n_gettext('848', 'Theses', 'ccvm', 'value'), FALSE),
4139     (1533, 'cont4', 'n',        oils_i18n_gettext('849', 'Surveys of the literature in a subject area', 'ccvm', 'value'), FALSE),
4140     (1534, 'cont4', 'o',        oils_i18n_gettext('850', 'Reviews', 'ccvm', 'value'), FALSE),
4141     (1535, 'cont4', 'p',        oils_i18n_gettext('851', 'Programmed texts', 'ccvm', 'value'), FALSE),
4142     (1536, 'cont4', 'q',        oils_i18n_gettext('852', 'Filmographies', 'ccvm', 'value'), FALSE),
4143     (1537, 'cont4', 'r',        oils_i18n_gettext('853', 'Directories', 'ccvm', 'value'), FALSE),
4144     (1538, 'cont4', 's',        oils_i18n_gettext('854', 'Statistics', 'ccvm', 'value'), FALSE),
4145     (1539, 'cont4', 't',        oils_i18n_gettext('855', 'Technical reports', 'ccvm', 'value'), FALSE),
4146     (1540, 'cont4', 'u',        oils_i18n_gettext('856', 'Standards/specifications', 'ccvm', 'value'), FALSE),
4147     (1541, 'cont4', 'v',        oils_i18n_gettext('857', 'Legal cases and case notes', 'ccvm', 'value'), FALSE),
4148     (1542, 'cont4', 'w',        oils_i18n_gettext('858', 'Law reports and digests', 'ccvm', 'value'), FALSE),
4149     (1543, 'cont4', 'x',        oils_i18n_gettext('859', 'Other reports', 'ccvm', 'value'), FALSE),
4150     (1544, 'cont4', 'y',        oils_i18n_gettext('860', 'Yearbooks', 'ccvm', 'value'), FALSE),
4151     (1545, 'cont4', 'z',        oils_i18n_gettext('861', 'Treaties', 'ccvm', 'value'), FALSE),
4152     (1546, 'cont4', '2',        oils_i18n_gettext('862', 'Offprints', 'ccvm', 'value'), FALSE),
4153     (1547, 'cont4', '5',        oils_i18n_gettext('863', 'Calendars', 'ccvm', 'value'), FALSE),
4154     (1548, 'cont4', '6',        oils_i18n_gettext('864', 'Comics/graphic novels', 'ccvm', 'value'), FALSE),
4155         
4156     (1549, 'ltxt1', ' ',        oils_i18n_gettext('881', 'Item is a music sound recording', 'ccvm', 'value'), FALSE),
4157     (1550, 'ltxt1', 'a',        oils_i18n_gettext('882', 'Autobiography', 'ccvm', 'value'), FALSE),
4158     (1551, 'ltxt1', 'b',        oils_i18n_gettext('883', 'Biography', 'ccvm', 'value'), FALSE),
4159     (1552, 'ltxt1', 'c',        oils_i18n_gettext('884', 'Conference proceedings', 'ccvm', 'value'), FALSE),
4160     (1553, 'ltxt1', 'd',        oils_i18n_gettext('885', 'Drama', 'ccvm', 'value'), FALSE),
4161     (1554, 'ltxt1', 'e',        oils_i18n_gettext('886', 'Essays', 'ccvm', 'value'), FALSE),
4162     (1555, 'ltxt1', 'f',        oils_i18n_gettext('887', 'Fiction', 'ccvm', 'value'), FALSE),
4163     (1556, 'ltxt1', 'g',        oils_i18n_gettext('888', 'Reporting', 'ccvm', 'value'), FALSE),
4164     (1557, 'ltxt1', 'h',        oils_i18n_gettext('889', 'History', 'ccvm', 'value'), FALSE),
4165     (1558, 'ltxt1', 'i',        oils_i18n_gettext('890', 'Instruction', 'ccvm', 'value'), FALSE),
4166     (1559, 'ltxt1', 'j',        oils_i18n_gettext('891', 'Language instruction', 'ccvm', 'value'), FALSE),
4167     (1560, 'ltxt1', 'k',        oils_i18n_gettext('892', 'Comedy', 'ccvm', 'value'), FALSE),
4168     (1561, 'ltxt1', 'l',        oils_i18n_gettext('893', 'Lectures, speeches', 'ccvm', 'value'), FALSE),
4169     (1562, 'ltxt1', 'm',        oils_i18n_gettext('894', 'Memoirs', 'ccvm', 'value'), FALSE),
4170     (1563, 'ltxt1', 'n',        oils_i18n_gettext('895', 'Not applicable', 'ccvm', 'value'), FALSE),
4171     (1564, 'ltxt1', 'o',        oils_i18n_gettext('896', 'Folktales', 'ccvm', 'value'), FALSE),
4172     (1565, 'ltxt1', 'p',        oils_i18n_gettext('897', 'Poetry', 'ccvm', 'value'), FALSE),
4173     (1566, 'ltxt1', 'r',        oils_i18n_gettext('898', 'Rehearsals', 'ccvm', 'value'), FALSE),
4174     (1567, 'ltxt1', 's',        oils_i18n_gettext('899', 'Sounds', 'ccvm', 'value'), FALSE),
4175     (1568, 'ltxt1', 't',        oils_i18n_gettext('900', 'Interviews', 'ccvm', 'value'), FALSE),
4176     (1569, 'ltxt1', 'z',        oils_i18n_gettext('901', 'Other', 'ccvm', 'value'), FALSE),
4177         
4178     (1570, 'ltxt2', 'a',        oils_i18n_gettext('882', 'Autobiography', 'ccvm', 'value'), FALSE),
4179     (1571, 'ltxt2', 'b',        oils_i18n_gettext('883', 'Biography', 'ccvm', 'value'), FALSE),
4180     (1572, 'ltxt2', 'c',        oils_i18n_gettext('884', 'Conference proceedings', 'ccvm', 'value'), FALSE),
4181     (1573, 'ltxt2', 'd',        oils_i18n_gettext('885', 'Drama', 'ccvm', 'value'), FALSE),
4182     (1574, 'ltxt2', 'e',        oils_i18n_gettext('886', 'Essays', 'ccvm', 'value'), FALSE),
4183     (1575, 'ltxt2', 'f',        oils_i18n_gettext('887', 'Fiction', 'ccvm', 'value'), FALSE),
4184     (1576, 'ltxt2', 'g',        oils_i18n_gettext('888', 'Reporting', 'ccvm', 'value'), FALSE),
4185     (1577, 'ltxt2', 'h',        oils_i18n_gettext('889', 'History', 'ccvm', 'value'), FALSE),
4186     (1578, 'ltxt2', 'i',        oils_i18n_gettext('890', 'Instruction', 'ccvm', 'value'), FALSE),
4187     (1579, 'ltxt2', 'j',        oils_i18n_gettext('891', 'Language instruction', 'ccvm', 'value'), FALSE),
4188     (1580, 'ltxt2', 'k',        oils_i18n_gettext('892', 'Comedy', 'ccvm', 'value'), FALSE),
4189     (1581, 'ltxt2', 'l',        oils_i18n_gettext('893', 'Lectures, speeches', 'ccvm', 'value'), FALSE),
4190     (1582, 'ltxt2', 'm',        oils_i18n_gettext('894', 'Memoirs', 'ccvm', 'value'), FALSE),
4191     (1583, 'ltxt2', 'n',        oils_i18n_gettext('895', 'Not applicable', 'ccvm', 'value'), FALSE),
4192     (1584, 'ltxt2', 'o',        oils_i18n_gettext('896', 'Folktales', 'ccvm', 'value'), FALSE),
4193     (1585, 'ltxt2', 'p',        oils_i18n_gettext('897', 'Poetry', 'ccvm', 'value'), FALSE),
4194     (1586, 'ltxt2', 'r',        oils_i18n_gettext('898', 'Rehearsals', 'ccvm', 'value'), FALSE),
4195     (1587, 'ltxt2', 's',        oils_i18n_gettext('899', 'Sounds', 'ccvm', 'value'), FALSE),
4196     (1588, 'ltxt2', 't',        oils_i18n_gettext('900', 'Interviews', 'ccvm', 'value'), FALSE),
4197     (1589, 'ltxt2', 'z',        oils_i18n_gettext('901', 'Other', 'ccvm', 'value'), FALSE),
4198         
4199     (1590, 'relf1', ' ',        oils_i18n_gettext('965', 'No relief shown', 'ccvm', 'value'), FALSE),
4200     (1591, 'relf1', 'a',        oils_i18n_gettext('966', 'Contours', 'ccvm', 'value'), FALSE),
4201     (1592, 'relf1', 'b',        oils_i18n_gettext('967', 'Shading', 'ccvm', 'value'), FALSE),
4202     (1593, 'relf1', 'c',        oils_i18n_gettext('968', 'Gradient and bathymetric tints', 'ccvm', 'value'), FALSE),
4203     (1594, 'relf1', 'd',        oils_i18n_gettext('969', 'Hachures', 'ccvm', 'value'), FALSE),
4204     (1595, 'relf1', 'e',        oils_i18n_gettext('970', 'Bathymetry, soundings', 'ccvm', 'value'), FALSE),
4205     (1596, 'relf1', 'f',        oils_i18n_gettext('971', 'Form lines', 'ccvm', 'value'), FALSE),
4206     (1597, 'relf1', 'g',        oils_i18n_gettext('972', 'Spot heights', 'ccvm', 'value'), FALSE),
4207     (1598, 'relf1', 'i',        oils_i18n_gettext('973', 'Pictorially', 'ccvm', 'value'), FALSE),
4208     (1599, 'relf1', 'j',        oils_i18n_gettext('974', 'Land forms', 'ccvm', 'value'), FALSE),
4209     (1600, 'relf1', 'k',        oils_i18n_gettext('975', 'Bathymetry, isolines', 'ccvm', 'value'), FALSE),
4210     (1601, 'relf1', 'm',        oils_i18n_gettext('976', 'Rock drawings', 'ccvm', 'value'), FALSE),
4211     (1602, 'relf1', 'z',        oils_i18n_gettext('977', 'Other', 'ccvm', 'value'), FALSE),
4212         
4213     (1603, 'relf2', 'a',        oils_i18n_gettext('966', 'Contours', 'ccvm', 'value'), FALSE),
4214     (1604, 'relf2', 'b',        oils_i18n_gettext('967', 'Shading', 'ccvm', 'value'), FALSE),
4215     (1605, 'relf2', 'c',        oils_i18n_gettext('968', 'Gradient and bathymetric tints', 'ccvm', 'value'), FALSE),
4216     (1606, 'relf2', 'd',        oils_i18n_gettext('969', 'Hachures', 'ccvm', 'value'), FALSE),
4217     (1607, 'relf2', 'e',        oils_i18n_gettext('970', 'Bathymetry, soundings', 'ccvm', 'value'), FALSE),
4218     (1608, 'relf2', 'f',        oils_i18n_gettext('971', 'Form lines', 'ccvm', 'value'), FALSE),
4219     (1609, 'relf2', 'g',        oils_i18n_gettext('972', 'Spot heights', 'ccvm', 'value'), FALSE),
4220     (1610, 'relf2', 'i',        oils_i18n_gettext('973', 'Pictorially', 'ccvm', 'value'), FALSE),
4221     (1611, 'relf2', 'j',        oils_i18n_gettext('974', 'Land forms', 'ccvm', 'value'), FALSE),
4222     (1612, 'relf2', 'k',        oils_i18n_gettext('975', 'Bathymetry, isolines', 'ccvm', 'value'), FALSE),
4223     (1613, 'relf2', 'm',        oils_i18n_gettext('976', 'Rock drawings', 'ccvm', 'value'), FALSE),
4224     (1614, 'relf2', 'z',        oils_i18n_gettext('977', 'Other', 'ccvm', 'value'), FALSE),
4225         
4226     (1615, 'relf3', 'a',        oils_i18n_gettext('966', 'Contours', 'ccvm', 'value'), FALSE),
4227     (1616, 'relf3', 'b',        oils_i18n_gettext('967', 'Shading', 'ccvm', 'value'), FALSE),
4228     (1617, 'relf3', 'c',        oils_i18n_gettext('968', 'Gradient and bathymetric tints', 'ccvm', 'value'), FALSE),
4229     (1618, 'relf3', 'd',        oils_i18n_gettext('969', 'Hachures', 'ccvm', 'value'), FALSE),
4230     (1619, 'relf3', 'e',        oils_i18n_gettext('970', 'Bathymetry, soundings', 'ccvm', 'value'), FALSE),
4231     (1620, 'relf3', 'f',        oils_i18n_gettext('971', 'Form lines', 'ccvm', 'value'), FALSE),
4232     (1621, 'relf3', 'g',        oils_i18n_gettext('972', 'Spot heights', 'ccvm', 'value'), FALSE),
4233     (1622, 'relf3', 'i',        oils_i18n_gettext('973', 'Pictorially', 'ccvm', 'value'), FALSE),
4234     (1623, 'relf3', 'j',        oils_i18n_gettext('974', 'Land forms', 'ccvm', 'value'), FALSE),
4235     (1624, 'relf3', 'k',        oils_i18n_gettext('975', 'Bathymetry, isolines', 'ccvm', 'value'), FALSE),
4236     (1625, 'relf3', 'm',        oils_i18n_gettext('976', 'Rock drawings', 'ccvm', 'value'), FALSE),
4237     (1626, 'relf3', 'z',        oils_i18n_gettext('977', 'Other', 'ccvm', 'value'), FALSE),
4238         
4239     (1627, 'relf4', 'a',        oils_i18n_gettext('966', 'Contours', 'ccvm', 'value'), FALSE),
4240     (1628, 'relf4', 'b',        oils_i18n_gettext('967', 'Shading', 'ccvm', 'value'), FALSE),
4241     (1629, 'relf4', 'c',        oils_i18n_gettext('968', 'Gradient and bathymetric tints', 'ccvm', 'value'), FALSE),
4242     (1630, 'relf4', 'd',        oils_i18n_gettext('969', 'Hachures', 'ccvm', 'value'), FALSE),
4243     (1631, 'relf4', 'e',        oils_i18n_gettext('970', 'Bathymetry, soundings', 'ccvm', 'value'), FALSE),
4244     (1632, 'relf4', 'f',        oils_i18n_gettext('971', 'Form lines', 'ccvm', 'value'), FALSE),
4245     (1633, 'relf4', 'g',        oils_i18n_gettext('972', 'Spot heights', 'ccvm', 'value'), FALSE),
4246     (1634, 'relf4', 'i',        oils_i18n_gettext('973', 'Pictorially', 'ccvm', 'value'), FALSE),
4247     (1635, 'relf4', 'j',        oils_i18n_gettext('974', 'Land forms', 'ccvm', 'value'), FALSE),
4248     (1636, 'relf4', 'k',        oils_i18n_gettext('975', 'Bathymetry, isolines', 'ccvm', 'value'), FALSE),
4249     (1637, 'relf4', 'm',        oils_i18n_gettext('976', 'Rock drawings', 'ccvm', 'value'), FALSE),
4250     (1638, 'relf4', 'z',        oils_i18n_gettext('977', 'Other', 'ccvm', 'value'), FALSE),
4251         
4252     (1639, 'spfm1', ' ',        oils_i18n_gettext('978', 'No specified special format characteristics', 'ccvm', 'value'), FALSE),
4253     (1640, 'spfm1', 'e',        oils_i18n_gettext('979', 'Manuscript', 'ccvm', 'value'), FALSE),
4254     (1641, 'spfm1', 'j',        oils_i18n_gettext('980', 'Picture card, post card', 'ccvm', 'value'), FALSE),
4255     (1642, 'spfm1', 'k',        oils_i18n_gettext('981', 'Calendar', 'ccvm', 'value'), FALSE),
4256     (1643, 'spfm1', 'l',        oils_i18n_gettext('982', 'Puzzle', 'ccvm', 'value'), FALSE),
4257     (1644, 'spfm1', 'n',        oils_i18n_gettext('983', 'Game', 'ccvm', 'value'), FALSE),
4258     (1645, 'spfm1', 'o',        oils_i18n_gettext('984', 'Wall map', 'ccvm', 'value'), FALSE),
4259     (1646, 'spfm1', 'p',        oils_i18n_gettext('985', 'Playing cards', 'ccvm', 'value'), FALSE),
4260     (1647, 'spfm1', 'r',        oils_i18n_gettext('986', 'Loose-leaf', 'ccvm', 'value'), FALSE),
4261     (1648, 'spfm1', 'z',        oils_i18n_gettext('987', 'Other', 'ccvm', 'value'), FALSE),
4262         
4263     (1649, 'spfm2', 'e',        oils_i18n_gettext('979', 'Manuscript', 'ccvm', 'value'), FALSE),
4264     (1650, 'spfm2', 'j',        oils_i18n_gettext('980', 'Picture card, post card', 'ccvm', 'value'), FALSE),
4265     (1651, 'spfm2', 'k',        oils_i18n_gettext('981', 'Calendar', 'ccvm', 'value'), FALSE),
4266     (1652, 'spfm2', 'l',        oils_i18n_gettext('982', 'Puzzle', 'ccvm', 'value'), FALSE),
4267     (1653, 'spfm2', 'n',        oils_i18n_gettext('983', 'Game', 'ccvm', 'value'), FALSE),
4268     (1654, 'spfm2', 'o',        oils_i18n_gettext('984', 'Wall map', 'ccvm', 'value'), FALSE),
4269     (1655, 'spfm2', 'p',        oils_i18n_gettext('985', 'Playing cards', 'ccvm', 'value'), FALSE),
4270     (1656, 'spfm2', 'r',        oils_i18n_gettext('986', 'Loose-leaf', 'ccvm', 'value'), FALSE),
4271     (1657, 'spfm2', 'z',        oils_i18n_gettext('987', 'Other', 'ccvm', 'value'), FALSE),
4272         
4273     (1658, 'ills', ' ',         oils_i18n_gettext('1658', 'No Illustrations', 'ccvm', 'value'), FALSE),
4274     (1659, 'ills', 'a',         oils_i18n_gettext('1659', 'Illustrations', 'ccvm', 'value'), FALSE),
4275     (1660, 'ills', 'b',         oils_i18n_gettext('1660', 'Maps', 'ccvm', 'value'), FALSE),
4276     (1661, 'ills', 'c',         oils_i18n_gettext('1661', 'Portraits', 'ccvm', 'value'), FALSE),
4277     (1662, 'ills', 'd',         oils_i18n_gettext('1662', 'Charts', 'ccvm', 'value'), FALSE),
4278     (1663, 'ills', 'e',         oils_i18n_gettext('1663', 'Plans', 'ccvm', 'value'), FALSE),
4279     (1664, 'ills', 'f',         oils_i18n_gettext('1664', 'Plates', 'ccvm', 'value'), FALSE),
4280     (1665, 'ills', 'g',         oils_i18n_gettext('1665', 'Music', 'ccvm', 'value'), FALSE),
4281     (1666, 'ills', 'h',         oils_i18n_gettext('1666', 'Facsimiles', 'ccvm', 'value'), FALSE),
4282     (1667, 'ills', 'i',         oils_i18n_gettext('1667', 'Coats of arms', 'ccvm', 'value'), FALSE),
4283     (1668, 'ills', 'j',         oils_i18n_gettext('1668', 'Genealogical tables', 'ccvm', 'value'), FALSE),
4284     (1669, 'ills', 'k',         oils_i18n_gettext('1669', 'Forms', 'ccvm', 'value'), FALSE),
4285     (1670, 'ills', 'l',         oils_i18n_gettext('1670', 'Samples', 'ccvm', 'value'), FALSE),
4286     (1671, 'ills', 'm',         oils_i18n_gettext('1671', 'Phonodisc, phonowire, etc.', 'ccvm', 'value'), FALSE),
4287     (1672, 'ills', 'o',         oils_i18n_gettext('1672', 'Photographs', 'ccvm', 'value'), FALSE),
4288     (1673, 'ills', 'p',         oils_i18n_gettext('1673', 'Illuminations', 'ccvm', 'value'), FALSE),
4289         
4290     (1674, 'ills1', ' ',        oils_i18n_gettext('1658', 'No Illustrations', 'ccvm', 'value'), FALSE),
4291     (1675, 'ills1', 'a',        oils_i18n_gettext('1659', 'Illustrations', 'ccvm', 'value'), FALSE),
4292     (1676, 'ills1', 'b',        oils_i18n_gettext('1660', 'Maps', 'ccvm', 'value'), FALSE),
4293     (1677, 'ills1', 'c',        oils_i18n_gettext('1661', 'Portraits', 'ccvm', 'value'), FALSE),
4294     (1678, 'ills1', 'd',        oils_i18n_gettext('1662', 'Charts', 'ccvm', 'value'), FALSE),
4295     (1679, 'ills1', 'e',        oils_i18n_gettext('1663', 'Plans', 'ccvm', 'value'), FALSE),
4296     (1680, 'ills1', 'f',        oils_i18n_gettext('1664', 'Plates', 'ccvm', 'value'), FALSE),
4297     (1681, 'ills1', 'g',        oils_i18n_gettext('1665', 'Music', 'ccvm', 'value'), FALSE),
4298     (1682, 'ills1', 'h',        oils_i18n_gettext('1666', 'Facsimiles', 'ccvm', 'value'), FALSE),
4299     (1683, 'ills1', 'i',        oils_i18n_gettext('1667', 'Coats of arms', 'ccvm', 'value'), FALSE),
4300     (1684, 'ills1', 'j',        oils_i18n_gettext('1668', 'Genealogical tables', 'ccvm', 'value'), FALSE),
4301     (1685, 'ills1', 'k',        oils_i18n_gettext('1669', 'Forms', 'ccvm', 'value'), FALSE),
4302     (1686, 'ills1', 'l',        oils_i18n_gettext('1670', 'Samples', 'ccvm', 'value'), FALSE),
4303     (1687, 'ills1', 'm',        oils_i18n_gettext('1671', 'Phonodisc, phonowire, etc.', 'ccvm', 'value'), FALSE),
4304     (1688, 'ills1', 'o',        oils_i18n_gettext('1672', 'Photographs', 'ccvm', 'value'), FALSE),
4305     (1689, 'ills1', 'p',        oils_i18n_gettext('1673', 'Illuminations', 'ccvm', 'value'), FALSE),
4306         
4307     (1690, 'ills2', 'a',        oils_i18n_gettext('1659', 'Illustrations', 'ccvm', 'value'), FALSE),
4308     (1691, 'ills2', 'b',        oils_i18n_gettext('1660', 'Maps', 'ccvm', 'value'), FALSE),
4309     (1692, 'ills2', 'c',        oils_i18n_gettext('1661', 'Portraits', 'ccvm', 'value'), FALSE),
4310     (1693, 'ills2', 'd',        oils_i18n_gettext('1662', 'Charts', 'ccvm', 'value'), FALSE),
4311     (1694, 'ills2', 'e',        oils_i18n_gettext('1663', 'Plans', 'ccvm', 'value'), FALSE),
4312     (1695, 'ills2', 'f',        oils_i18n_gettext('1664', 'Plates', 'ccvm', 'value'), FALSE),
4313     (1696, 'ills2', 'g',        oils_i18n_gettext('1665', 'Music', 'ccvm', 'value'), FALSE),
4314     (1697, 'ills2', 'h',        oils_i18n_gettext('1666', 'Facsimiles', 'ccvm', 'value'), FALSE),
4315     (1698, 'ills2', 'i',        oils_i18n_gettext('1667', 'Coats of arms', 'ccvm', 'value'), FALSE),
4316     (1699, 'ills2', 'j',        oils_i18n_gettext('1668', 'Genealogical tables', 'ccvm', 'value'), FALSE),
4317     (1700, 'ills2', 'k',        oils_i18n_gettext('1669', 'Forms', 'ccvm', 'value'), FALSE),
4318     (1701, 'ills2', 'l',        oils_i18n_gettext('1670', 'Samples', 'ccvm', 'value'), FALSE),
4319     (1702, 'ills2', 'm',        oils_i18n_gettext('1671', 'Phonodisc, phonowire, etc.', 'ccvm', 'value'), FALSE),
4320     (1703, 'ills2', 'o',        oils_i18n_gettext('1672', 'Photographs', 'ccvm', 'value'), FALSE),
4321     (1704, 'ills2', 'p',        oils_i18n_gettext('1673', 'Illuminations', 'ccvm', 'value'), FALSE),
4322         
4323     (1705, 'ills3', 'a',        oils_i18n_gettext('1659', 'Illustrations', 'ccvm', 'value'), FALSE),
4324     (1706, 'ills3', 'b',        oils_i18n_gettext('1660', 'Maps', 'ccvm', 'value'), FALSE),
4325     (1707, 'ills3', 'c',        oils_i18n_gettext('1661', 'Portraits', 'ccvm', 'value'), FALSE),
4326     (1708, 'ills3', 'd',        oils_i18n_gettext('1662', 'Charts', 'ccvm', 'value'), FALSE),
4327     (1709, 'ills3', 'e',        oils_i18n_gettext('1663', 'Plans', 'ccvm', 'value'), FALSE),
4328     (1710, 'ills3', 'f',        oils_i18n_gettext('1664', 'Plates', 'ccvm', 'value'), FALSE),
4329     (1711, 'ills3', 'g',        oils_i18n_gettext('1665', 'Music', 'ccvm', 'value'), FALSE),
4330     (1712, 'ills3', 'h',        oils_i18n_gettext('1666', 'Facsimiles', 'ccvm', 'value'), FALSE),
4331     (1713, 'ills3', 'i',        oils_i18n_gettext('1667', 'Coats of arms', 'ccvm', 'value'), FALSE),
4332     (1714, 'ills3', 'j',        oils_i18n_gettext('1668', 'Genealogical tables', 'ccvm', 'value'), FALSE),
4333     (1715, 'ills3', 'k',        oils_i18n_gettext('1669', 'Forms', 'ccvm', 'value'), FALSE),
4334     (1716, 'ills3', 'l',        oils_i18n_gettext('1670', 'Samples', 'ccvm', 'value'), FALSE),
4335     (1717, 'ills3', 'm',        oils_i18n_gettext('1671', 'Phonodisc, phonowire, etc.', 'ccvm', 'value'), FALSE),
4336     (1718, 'ills3', 'o',        oils_i18n_gettext('1672', 'Photographs', 'ccvm', 'value'), FALSE),
4337     (1719, 'ills3', 'p',        oils_i18n_gettext('1673', 'Illuminations', 'ccvm', 'value'), FALSE),
4338         
4339     (1720, 'ills4', 'a',        oils_i18n_gettext('1659', 'Illustrations', 'ccvm', 'value'), FALSE),
4340     (1721, 'ills4', 'b',        oils_i18n_gettext('1660', 'Maps', 'ccvm', 'value'), FALSE),
4341     (1722, 'ills4', 'c',        oils_i18n_gettext('1661', 'Portraits', 'ccvm', 'value'), FALSE),
4342     (1723, 'ills4', 'd',        oils_i18n_gettext('1662', 'Charts', 'ccvm', 'value'), FALSE),
4343     (1724, 'ills4', 'e',        oils_i18n_gettext('1663', 'Plans', 'ccvm', 'value'), FALSE),
4344     (1725, 'ills4', 'f',        oils_i18n_gettext('1664', 'Plates', 'ccvm', 'value'), FALSE),
4345     (1726, 'ills4', 'g',        oils_i18n_gettext('1665', 'Music', 'ccvm', 'value'), FALSE),
4346     (1727, 'ills4', 'h',        oils_i18n_gettext('1666', 'Facsimiles', 'ccvm', 'value'), FALSE),
4347     (1728, 'ills4', 'i',        oils_i18n_gettext('1667', 'Coats of arms', 'ccvm', 'value'), FALSE),
4348     (1729, 'ills4', 'j',        oils_i18n_gettext('1668', 'Genealogical tables', 'ccvm', 'value'), FALSE),
4349     (1730, 'ills4', 'k',        oils_i18n_gettext('1669', 'Forms', 'ccvm', 'value'), FALSE),
4350     (1731, 'ills4', 'l',        oils_i18n_gettext('1670', 'Samples', 'ccvm', 'value'), FALSE),
4351     (1732, 'ills4', 'm',        oils_i18n_gettext('1671', 'Phonodisc, phonowire, etc.', 'ccvm', 'value'), FALSE),
4352     (1733, 'ills4', 'o',        oils_i18n_gettext('1672', 'Photographs', 'ccvm', 'value'), FALSE),
4353     (1734, 'ills4', 'p',        oils_i18n_gettext('1673', 'Illuminations', 'ccvm', 'value'), FALSE);
4354         
4355
4356 -- Composite coded value maps, this way the "primary" fixed field can be used in advanced searches without a ton of ORs and extra work.
4357 -- Space is used as a filler for any position other than the first, so for something to actually have "No accompanying matter," for example, specifically accm1 must = ' '.
4358 -- Any other value has the same meaning in any position.
4359 INSERT INTO config.composite_attr_entry_definition (coded_value, definition) VALUES
4360     (1735, '{"_attr":"accm1","_val":" "}'),
4361     (713, '[{"_attr":"accm6","_val":"a"},{"_attr":"accm5","_val":"a"},{"_attr":"accm4","_val":"a"},{"_attr":"accm3","_val":"a"},{"_attr":"accm2","_val":"a"},{"_attr":"accm1","_val":"a"}]'),
4362     (714, '[{"_attr":"accm6","_val":"b"},{"_attr":"accm5","_val":"b"},{"_attr":"accm4","_val":"b"},{"_attr":"accm3","_val":"b"},{"_attr":"accm2","_val":"b"},{"_attr":"accm1","_val":"b"}]'),
4363     (715, '[{"_attr":"accm6","_val":"c"},{"_attr":"accm5","_val":"c"},{"_attr":"accm4","_val":"c"},{"_attr":"accm3","_val":"c"},{"_attr":"accm2","_val":"c"},{"_attr":"accm1","_val":"c"}]'),
4364     (716, '[{"_attr":"accm6","_val":"d"},{"_attr":"accm5","_val":"d"},{"_attr":"accm4","_val":"d"},{"_attr":"accm3","_val":"d"},{"_attr":"accm2","_val":"d"},{"_attr":"accm1","_val":"d"}]'),
4365     (717, '[{"_attr":"accm6","_val":"e"},{"_attr":"accm5","_val":"e"},{"_attr":"accm4","_val":"e"},{"_attr":"accm3","_val":"e"},{"_attr":"accm2","_val":"e"},{"_attr":"accm1","_val":"e"}]'),
4366     (718, '[{"_attr":"accm6","_val":"f"},{"_attr":"accm5","_val":"f"},{"_attr":"accm4","_val":"f"},{"_attr":"accm3","_val":"f"},{"_attr":"accm2","_val":"f"},{"_attr":"accm1","_val":"f"}]'),
4367     (719, '[{"_attr":"accm6","_val":"g"},{"_attr":"accm5","_val":"g"},{"_attr":"accm4","_val":"g"},{"_attr":"accm3","_val":"g"},{"_attr":"accm2","_val":"g"},{"_attr":"accm1","_val":"g"}]'),
4368     (720, '[{"_attr":"accm6","_val":"h"},{"_attr":"accm5","_val":"h"},{"_attr":"accm4","_val":"h"},{"_attr":"accm3","_val":"h"},{"_attr":"accm2","_val":"h"},{"_attr":"accm1","_val":"h"}]'),
4369     (721, '[{"_attr":"accm6","_val":"i"},{"_attr":"accm5","_val":"i"},{"_attr":"accm4","_val":"i"},{"_attr":"accm3","_val":"i"},{"_attr":"accm2","_val":"i"},{"_attr":"accm1","_val":"i"}]'),
4370     (722, '[{"_attr":"accm6","_val":"k"},{"_attr":"accm5","_val":"k"},{"_attr":"accm4","_val":"k"},{"_attr":"accm3","_val":"k"},{"_attr":"accm2","_val":"k"},{"_attr":"accm1","_val":"k"}]'),
4371     (723, '[{"_attr":"accm6","_val":"r"},{"_attr":"accm5","_val":"r"},{"_attr":"accm4","_val":"r"},{"_attr":"accm3","_val":"r"},{"_attr":"accm2","_val":"r"},{"_attr":"accm1","_val":"r"}]'),
4372     (724, '[{"_attr":"accm6","_val":"s"},{"_attr":"accm5","_val":"s"},{"_attr":"accm4","_val":"s"},{"_attr":"accm3","_val":"s"},{"_attr":"accm2","_val":"s"},{"_attr":"accm1","_val":"s"}]'),
4373     (725, '[{"_attr":"accm6","_val":"z"},{"_attr":"accm5","_val":"z"},{"_attr":"accm4","_val":"z"},{"_attr":"accm3","_val":"z"},{"_attr":"accm2","_val":"z"},{"_attr":"accm1","_val":"z"}]'),
4374
4375     (835, '{"_attr":"cont1","_val":" "}'),
4376     (836, '[{"_attr":"cont4","_val":"a"},{"_attr":"cont3","_val":"a"},{"_attr":"cont2","_val":"a"},{"_attr":"cont1","_val":"a"}]'),
4377     (837, '[{"_attr":"cont4","_val":"b"},{"_attr":"cont3","_val":"b"},{"_attr":"cont2","_val":"b"},{"_attr":"cont1","_val":"b"}]'),
4378     (838, '[{"_attr":"cont4","_val":"c"},{"_attr":"cont3","_val":"c"},{"_attr":"cont2","_val":"c"},{"_attr":"cont1","_val":"c"}]'),
4379     (839, '[{"_attr":"cont4","_val":"d"},{"_attr":"cont3","_val":"d"},{"_attr":"cont2","_val":"d"},{"_attr":"cont1","_val":"d"}]'),
4380     (840, '[{"_attr":"cont4","_val":"e"},{"_attr":"cont3","_val":"e"},{"_attr":"cont2","_val":"e"},{"_attr":"cont1","_val":"e"}]'),
4381     (841, '[{"_attr":"cont4","_val":"f"},{"_attr":"cont3","_val":"f"},{"_attr":"cont2","_val":"f"},{"_attr":"cont1","_val":"f"}]'),
4382     (842, '[{"_attr":"cont4","_val":"g"},{"_attr":"cont3","_val":"g"},{"_attr":"cont2","_val":"g"},{"_attr":"cont1","_val":"g"}]'),
4383     (843, '[{"_attr":"cont4","_val":"h"},{"_attr":"cont3","_val":"h"},{"_attr":"cont2","_val":"h"},{"_attr":"cont1","_val":"h"}]'),
4384     (844, '[{"_attr":"cont4","_val":"i"},{"_attr":"cont3","_val":"i"},{"_attr":"cont2","_val":"i"},{"_attr":"cont1","_val":"i"}]'),
4385     (845, '[{"_attr":"cont4","_val":"j"},{"_attr":"cont3","_val":"j"},{"_attr":"cont2","_val":"j"},{"_attr":"cont1","_val":"j"}]'),
4386     (846, '[{"_attr":"cont4","_val":"k"},{"_attr":"cont3","_val":"k"},{"_attr":"cont2","_val":"k"},{"_attr":"cont1","_val":"k"}]'),
4387     (847, '[{"_attr":"cont4","_val":"l"},{"_attr":"cont3","_val":"l"},{"_attr":"cont2","_val":"l"},{"_attr":"cont1","_val":"l"}]'),
4388     (848, '[{"_attr":"cont4","_val":"m"},{"_attr":"cont3","_val":"m"},{"_attr":"cont2","_val":"m"},{"_attr":"cont1","_val":"m"}]'),
4389     (849, '[{"_attr":"cont4","_val":"n"},{"_attr":"cont3","_val":"n"},{"_attr":"cont2","_val":"n"},{"_attr":"cont1","_val":"n"}]'),
4390     (850, '[{"_attr":"cont4","_val":"o"},{"_attr":"cont3","_val":"o"},{"_attr":"cont2","_val":"o"},{"_attr":"cont1","_val":"o"}]'),
4391     (851, '[{"_attr":"cont4","_val":"p"},{"_attr":"cont3","_val":"p"},{"_attr":"cont2","_val":"p"},{"_attr":"cont1","_val":"p"}]'),
4392     (852, '[{"_attr":"cont4","_val":"q"},{"_attr":"cont3","_val":"q"},{"_attr":"cont2","_val":"q"},{"_attr":"cont1","_val":"q"}]'),
4393     (853, '[{"_attr":"cont4","_val":"r"},{"_attr":"cont3","_val":"r"},{"_attr":"cont2","_val":"r"},{"_attr":"cont1","_val":"r"}]'),
4394     (854, '[{"_attr":"cont4","_val":"s"},{"_attr":"cont3","_val":"s"},{"_attr":"cont2","_val":"s"},{"_attr":"cont1","_val":"s"}]'),
4395     (855, '[{"_attr":"cont4","_val":"t"},{"_attr":"cont3","_val":"t"},{"_attr":"cont2","_val":"t"},{"_attr":"cont1","_val":"t"}]'),
4396     (856, '[{"_attr":"cont4","_val":"u"},{"_attr":"cont3","_val":"u"},{"_attr":"cont2","_val":"u"},{"_attr":"cont1","_val":"u"}]'),
4397     (857, '[{"_attr":"cont4","_val":"v"},{"_attr":"cont3","_val":"v"},{"_attr":"cont2","_val":"v"},{"_attr":"cont1","_val":"v"}]'),
4398     (858, '[{"_attr":"cont4","_val":"w"},{"_attr":"cont3","_val":"w"},{"_attr":"cont2","_val":"w"},{"_attr":"cont1","_val":"w"}]'),
4399     (859, '[{"_attr":"cont4","_val":"x"},{"_attr":"cont3","_val":"x"},{"_attr":"cont2","_val":"x"},{"_attr":"cont1","_val":"x"}]'),
4400     (860, '[{"_attr":"cont4","_val":"y"},{"_attr":"cont3","_val":"y"},{"_attr":"cont2","_val":"y"},{"_attr":"cont1","_val":"y"}]'),
4401     (861, '[{"_attr":"cont4","_val":"z"},{"_attr":"cont3","_val":"z"},{"_attr":"cont2","_val":"z"},{"_attr":"cont1","_val":"z"}]'),
4402     (862, '[{"_attr":"cont4","_val":"2"},{"_attr":"cont3","_val":"2"},{"_attr":"cont2","_val":"2"},{"_attr":"cont1","_val":"2"}]'),
4403     (863, '[{"_attr":"cont4","_val":"5"},{"_attr":"cont3","_val":"5"},{"_attr":"cont2","_val":"5"},{"_attr":"cont1","_val":"5"}]'),
4404     (864, '[{"_attr":"cont4","_val":"6"},{"_attr":"cont3","_val":"6"},{"_attr":"cont2","_val":"6"},{"_attr":"cont1","_val":"6"}]'),
4405
4406     (881, '{"_attr":"ltxt1","_val":" "}'),
4407     (882, '[{"_attr":"ltxt2","_val":"a"},{"_attr":"ltxt1","_val":"a"}]'),
4408     (883, '[{"_attr":"ltxt2","_val":"b"},{"_attr":"ltxt1","_val":"b"}]'),
4409     (884, '[{"_attr":"ltxt2","_val":"c"},{"_attr":"ltxt1","_val":"c"}]'),
4410     (885, '[{"_attr":"ltxt2","_val":"d"},{"_attr":"ltxt1","_val":"d"}]'),
4411     (886, '[{"_attr":"ltxt2","_val":"e"},{"_attr":"ltxt1","_val":"e"}]'),
4412     (887, '[{"_attr":"ltxt2","_val":"f"},{"_attr":"ltxt1","_val":"f"}]'),
4413     (888, '[{"_attr":"ltxt2","_val":"g"},{"_attr":"ltxt1","_val":"g"}]'),
4414     (889, '[{"_attr":"ltxt2","_val":"h"},{"_attr":"ltxt1","_val":"h"}]'),
4415     (890, '[{"_attr":"ltxt2","_val":"i"},{"_attr":"ltxt1","_val":"i"}]'),
4416     (891, '[{"_attr":"ltxt2","_val":"j"},{"_attr":"ltxt1","_val":"j"}]'),
4417     (892, '[{"_attr":"ltxt2","_val":"k"},{"_attr":"ltxt1","_val":"k"}]'),
4418     (893, '[{"_attr":"ltxt2","_val":"l"},{"_attr":"ltxt1","_val":"l"}]'),
4419     (894, '[{"_attr":"ltxt2","_val":"m"},{"_attr":"ltxt1","_val":"m"}]'),
4420     (895, '[{"_attr":"ltxt2","_val":"n"},{"_attr":"ltxt1","_val":"n"}]'),
4421     (896, '[{"_attr":"ltxt2","_val":"o"},{"_attr":"ltxt1","_val":"o"}]'),
4422     (897, '[{"_attr":"ltxt2","_val":"p"},{"_attr":"ltxt1","_val":"p"}]'),
4423     (898, '[{"_attr":"ltxt2","_val":"r"},{"_attr":"ltxt1","_val":"r"}]'),
4424     (899, '[{"_attr":"ltxt2","_val":"s"},{"_attr":"ltxt1","_val":"s"}]'),
4425     (900, '[{"_attr":"ltxt2","_val":"t"},{"_attr":"ltxt1","_val":"t"}]'),
4426     (901, '[{"_attr":"ltxt2","_val":"z"},{"_attr":"ltxt1","_val":"z"}]'),
4427
4428     (965, '{"_attr":"relf1","_val":" "}'),
4429     (966, '[{"_attr":"relf4","_val":"a"},{"_attr":"relf3","_val":"a"},{"_attr":"relf2","_val":"a"},{"_attr":"relf1","_val":"a"}]'),
4430     (967, '[{"_attr":"relf4","_val":"b"},{"_attr":"relf3","_val":"b"},{"_attr":"relf2","_val":"b"},{"_attr":"relf1","_val":"b"}]'),
4431     (968, '[{"_attr":"relf4","_val":"c"},{"_attr":"relf3","_val":"c"},{"_attr":"relf2","_val":"c"},{"_attr":"relf1","_val":"c"}]'),
4432     (969, '[{"_attr":"relf4","_val":"d"},{"_attr":"relf3","_val":"d"},{"_attr":"relf2","_val":"d"},{"_attr":"relf1","_val":"d"}]'),
4433     (970, '[{"_attr":"relf4","_val":"e"},{"_attr":"relf3","_val":"e"},{"_attr":"relf2","_val":"e"},{"_attr":"relf1","_val":"e"}]'),
4434     (971, '[{"_attr":"relf4","_val":"f"},{"_attr":"relf3","_val":"f"},{"_attr":"relf2","_val":"f"},{"_attr":"relf1","_val":"f"}]'),
4435     (972, '[{"_attr":"relf4","_val":"g"},{"_attr":"relf3","_val":"g"},{"_attr":"relf2","_val":"g"},{"_attr":"relf1","_val":"g"}]'),
4436     (973, '[{"_attr":"relf4","_val":"i"},{"_attr":"relf3","_val":"i"},{"_attr":"relf2","_val":"i"},{"_attr":"relf1","_val":"i"}]'),
4437     (974, '[{"_attr":"relf4","_val":"j"},{"_attr":"relf3","_val":"j"},{"_attr":"relf2","_val":"j"},{"_attr":"relf1","_val":"j"}]'),
4438     (975, '[{"_attr":"relf4","_val":"k"},{"_attr":"relf3","_val":"k"},{"_attr":"relf2","_val":"k"},{"_attr":"relf1","_val":"k"}]'),
4439     (976, '[{"_attr":"relf4","_val":"m"},{"_attr":"relf3","_val":"m"},{"_attr":"relf2","_val":"m"},{"_attr":"relf1","_val":"m"}]'),
4440     (977, '[{"_attr":"relf4","_val":"z"},{"_attr":"relf3","_val":"z"},{"_attr":"relf2","_val":"z"},{"_attr":"relf1","_val":"z"}]'),
4441
4442     (978, '{"_attr":"spfm1","_val":" "}'),
4443     (979, '[{"_attr":"spfm2","_val":"e"},{"_attr":"spfm1","_val":"e"}]'),
4444     (980, '[{"_attr":"spfm2","_val":"j"},{"_attr":"spfm1","_val":"j"}]'),
4445     (981, '[{"_attr":"spfm2","_val":"k"},{"_attr":"spfm1","_val":"k"}]'),
4446     (982, '[{"_attr":"spfm2","_val":"l"},{"_attr":"spfm1","_val":"l"}]'),
4447     (983, '[{"_attr":"spfm2","_val":"n"},{"_attr":"spfm1","_val":"n"}]'),
4448     (984, '[{"_attr":"spfm2","_val":"o"},{"_attr":"spfm1","_val":"o"}]'),
4449     (985, '[{"_attr":"spfm2","_val":"p"},{"_attr":"spfm1","_val":"p"}]'),
4450     (986, '[{"_attr":"spfm2","_val":"r"},{"_attr":"spfm1","_val":"r"}]'),
4451     (987, '[{"_attr":"spfm2","_val":"z"},{"_attr":"spfm1","_val":"z"}]'),
4452         
4453     (1658, '{"_attr":"ills1","_val":" "}'),
4454     (1659, '[{"_attr":"ills4","_val":"a"},{"_attr":"ills3","_val":"a"},{"_attr":"ills2","_val":"a"},{"_attr":"ills1","_val":"a"}]'),
4455     (1660, '[{"_attr":"ills4","_val":"b"},{"_attr":"ills3","_val":"b"},{"_attr":"ills2","_val":"b"},{"_attr":"ills1","_val":"b"}]'),
4456     (1661, '[{"_attr":"ills4","_val":"c"},{"_attr":"ills3","_val":"c"},{"_attr":"ills2","_val":"c"},{"_attr":"ills1","_val":"c"}]'),
4457     (1662, '[{"_attr":"ills4","_val":"d"},{"_attr":"ills3","_val":"d"},{"_attr":"ills2","_val":"d"},{"_attr":"ills1","_val":"d"}]'),
4458     (1663, '[{"_attr":"ills4","_val":"e"},{"_attr":"ills3","_val":"e"},{"_attr":"ills2","_val":"e"},{"_attr":"ills1","_val":"e"}]'),
4459     (1664, '[{"_attr":"ills4","_val":"f"},{"_attr":"ills3","_val":"f"},{"_attr":"ills2","_val":"f"},{"_attr":"ills1","_val":"f"}]'),
4460     (1665, '[{"_attr":"ills4","_val":"g"},{"_attr":"ills3","_val":"g"},{"_attr":"ills2","_val":"g"},{"_attr":"ills1","_val":"g"}]'),
4461     (1666, '[{"_attr":"ills4","_val":"h"},{"_attr":"ills3","_val":"h"},{"_attr":"ills2","_val":"h"},{"_attr":"ills1","_val":"h"}]'),
4462     (1667, '[{"_attr":"ills4","_val":"i"},{"_attr":"ills3","_val":"i"},{"_attr":"ills2","_val":"i"},{"_attr":"ills1","_val":"i"}]'),
4463     (1668, '[{"_attr":"ills4","_val":"j"},{"_attr":"ills3","_val":"j"},{"_attr":"ills2","_val":"j"},{"_attr":"ills1","_val":"j"}]'),
4464     (1669, '[{"_attr":"ills4","_val":"k"},{"_attr":"ills3","_val":"k"},{"_attr":"ills2","_val":"k"},{"_attr":"ills1","_val":"k"}]'),
4465     (1670, '[{"_attr":"ills4","_val":"l"},{"_attr":"ills3","_val":"l"},{"_attr":"ills2","_val":"l"},{"_attr":"ills1","_val":"l"}]'),
4466     (1671, '[{"_attr":"ills4","_val":"m"},{"_attr":"ills3","_val":"m"},{"_attr":"ills2","_val":"m"},{"_attr":"ills1","_val":"m"}]'),
4467     (1672, '[{"_attr":"ills4","_val":"o"},{"_attr":"ills3","_val":"o"},{"_attr":"ills2","_val":"o"},{"_attr":"ills1","_val":"o"}]'),
4468     (1673, '[{"_attr":"ills4","_val":"p"},{"_attr":"ills3","_val":"p"},{"_attr":"ills2","_val":"p"},{"_attr":"ills1","_val":"p"}]');
4469
4470 SELECT evergreen.upgrade_deps_block_check('0968', :eg_version); -- jstompro/gmcharlt
4471
4472 --create hook for actor.usr.create_date
4473 INSERT INTO action_trigger.hook (key, core_type, description, passive)
4474     VALUES ('au.created', 'au', 'A user was created', 't');
4475         
4476 --SQL to create event definition for new account creation notice
4477 --Inactive, owned by top of org tree by default.  Modify to suit needs.
4478
4479 INSERT INTO action_trigger.event_definition (
4480     active, owner, name, hook, 
4481     validator, reactor, delay, delay_field,
4482     max_delay, template
4483 )  VALUES (
4484     'f', '1', 'New User Created Welcome Notice', 'au.created',
4485     'NOOP_True', 'SendEmail', '10 seconds', 'create_date',
4486     '1 day',
4487 $$
4488 [%- USE date -%]
4489 [%- user = target -%]
4490 [%- lib = target.home_ou -%]
4491 To: [%- params.recipient_email || user.email %]
4492 From: [%- helpers.get_org_setting(target.home_ou.id, 'org.bounced_emails') || lib.email || params.sender_email || default_sender %]
4493 Reply-To: [%- helpers.get_org_setting(target.home_ou.id, 'org.bounced_emails') || lib.email || params.sender_email || default_sender %]
4494 Subject: New Library Account Sign-up - Welcome!
4495 Auto-Submitted: auto-generated
4496
4497 Dear [% user.first_given_name %] [% user.family_name %],
4498
4499 Thank you for signing up for an account with the [% lib.name %] on [% user.create_date.substr(0, 10) %].
4500
4501 This email is your confirmation that your account is set up and ready as well as testing to see that we have your correct email address.
4502
4503 If you did not sign up for an account at the library and have received this email in error, please reply and let us know.
4504
4505 You can access your account online at http://catalog/eg/opac/login. From that site you can search the catalog, request materials, renew materials, leave comments, leave suggestions for titles you would like the library to purchase and update your account information.
4506
4507 Sincerely,
4508 [% lib.name %]
4509
4510 Contact your library for more information:
4511
4512 [% lib.name %]
4513 [%- SET addr = lib.mailing_address -%]
4514 [%- IF !addr -%] [%- SET addr = lib.billing_address -%] [%- END %]
4515 [% addr.street1 %] [% addr.street2 %]
4516 [% addr.city %], [% addr.state %]
4517 [% addr.post_code %]
4518 [% lib.phone %]
4519 [% lib.email %]
4520
4521 $$);
4522         
4523 --insert environment values
4524 INSERT INTO action_trigger.environment (event_def, path) VALUES
4525     (CURRVAL('action_trigger.event_definition_id_seq'), 'home_ou.mailing_address'),
4526     (CURRVAL('action_trigger.event_definition_id_seq'), 'home_ou.billing_address');
4527         
4528 SELECT evergreen.upgrade_deps_block_check('0969', :eg_version); -- jeffdavis/stompro
4529
4530 INSERT INTO config.org_unit_setting_type
4531     (name, grp, label, description, datatype)
4532     VALUES
4533         ('org.restrict_opt_to_depth',
4534          'sec',
4535          oils_i18n_gettext('org.restrict_opt_to_depth',
4536             'Restrict patron opt-in to home library and related orgs at specified depth',
4537             'coust', 'label'),
4538          oils_i18n_gettext('org.restrict_opt_to_depth',
4539             'Patrons at this library can only be opted-in at org units which are within the '||
4540             'library''s section of the org tree, at or below the depth specified by this setting. '||
4541             'They cannot be opted in at any other libraries.',
4542             'coust', 'description'),
4543         'integer');
4544
4545 SELECT evergreen.upgrade_deps_block_check('0970', :eg_version); -- Dyrcona/gmcharlt
4546
4547 CREATE OR REPLACE FUNCTION search.facets_for_record_set(ignore_facet_classes TEXT[], hits BIGINT[]) RETURNS TABLE (id INT, value TEXT, count BIGINT) AS $$
4548     SELECT id, value, count FROM (
4549         SELECT mfae.field AS id,
4550                mfae.value,
4551                COUNT(DISTINCT mmrsm.source),
4552                row_number() OVER (
4553                 PARTITION BY mfae.field ORDER BY COUNT(distinct mmrsm.source) DESC
4554                ) AS rownum
4555         FROM metabib.facet_entry mfae
4556         JOIN metabib.metarecord_source_map mmrsm ON (mfae.source = mmrsm.source)
4557         JOIN config.metabib_field cmf ON (cmf.id = mfae.field)
4558         WHERE mmrsm.source IN (SELECT * FROM unnest($2))
4559         AND cmf.facet_field
4560         AND cmf.field_class NOT IN (SELECT * FROM unnest($1))
4561         GROUP by 1, 2
4562     ) all_facets
4563     WHERE rownum <= (SELECT COALESCE((SELECT value::INT FROM config.global_flag WHERE name = 'search.max_facets_per_field' AND enabled), 1000));
4564 $$ LANGUAGE SQL;
4565
4566 CREATE OR REPLACE FUNCTION search.facets_for_metarecord_set(ignore_facet_classes TEXT[], hits BIGINT[]) RETURNS TABLE (id INT, value TEXT, count BIGINT) AS $$
4567     SELECT id, value, count FROM (
4568         SELECT mfae.field AS id,
4569                mfae.value,
4570                COUNT(DISTINCT mmrsm.metarecord),
4571                row_number() OVER (
4572                 PARTITION BY mfae.field ORDER BY COUNT(distinct mmrsm.metarecord) DESC
4573                ) AS rownum
4574         FROM metabib.facet_entry mfae
4575         JOIN metabib.metarecord_source_map mmrsm ON (mfae.source = mmrsm.source)
4576         JOIN config.metabib_field cmf ON (cmf.id = mfae.field)
4577         WHERE mmrsm.metarecord IN (SELECT * FROM unnest($2))
4578         AND cmf.facet_field
4579         AND cmf.field_class NOT IN (SELECT * FROM unnest($1))
4580         GROUP by 1, 2
4581     ) all_facets
4582     WHERE rownum <= (SELECT COALESCE((SELECT value::INT FROM config.global_flag WHERE name = 'search.max_facets_per_field' AND enabled), 1000));
4583 $$ LANGUAGE SQL;
4584
4585 COMMIT;
4586
4587 -- The following updates/inserts are allowed to fail
4588
4589 INSERT INTO config.index_normalizer (name, description, func, param_count) VALUES (
4590         'Number or NULL Normalize',
4591         'Normalize the value to NULL if it is not a number',
4592         'integer_or_null',
4593         0
4594 );
4595
4596 INSERT INTO config.index_normalizer (name, description, func, param_count) VALUES (
4597         'Approximate Low Date Normalize',
4598         'Normalize the value to the nearest date-ish value, rounding down',
4599         'approximate_low_date',
4600         0
4601 );
4602
4603 INSERT INTO config.index_normalizer (name, description, func, param_count) VALUES (
4604         'Approximate High Date Normalize',
4605         'Normalize the value to the nearest date-ish value, rounding up',
4606         'approximate_high_date',
4607         0
4608 );
4609
4610 INSERT INTO config.record_attr_index_norm_map (attr,norm,pos)
4611     SELECT  m.name, i.id, 0
4612       FROM  config.record_attr_definition m,
4613             config.index_normalizer i
4614       WHERE i.func IN ('integer_or_null')
4615             AND m.name IN ('date2', 'pubdate');
4616
4617 INSERT INTO config.record_attr_index_norm_map (attr,norm,pos)
4618     SELECT  m.name, i.id, 0
4619       FROM  config.record_attr_definition m,
4620             config.index_normalizer i
4621       WHERE i.func IN ('approximate_low_date')
4622             AND m.name IN ('date1');
4623
4624 INSERT INTO config.record_attr_index_norm_map (attr,norm,pos)
4625     SELECT  m.name, i.id, 0
4626       FROM  config.record_attr_definition m,
4627             config.index_normalizer i
4628       WHERE i.func IN ('approximate_high_date')
4629             AND m.name IN ('date2');
4630
4631 -- Get rid of bad date1 sorter values so we can avoid a reingest
4632 DELETE FROM metabib.record_sorter WHERE attr = 'pubdate' AND value !~ '^\d+$';
4633
4634 -- and these are reingests that are allowed be interrupted
4635 \qecho
4636 \qecho To use the new identifier|genre index, it is necessary to do
4637 \qecho a partial reingest of records that have a 655 tag. You can
4638 \qecho cancel out of this if you wish and run this and the following
4639 \qecho attribute reingest later.
4640 \qecho
4641 SELECT metabib.reingest_metabib_field_entries(record, FALSE, TRUE, FALSE)
4642 FROM metabib.real_full_rec
4643 WHERE tag IN ('655')
4644 GROUP BY record;
4645
4646 \qecho
4647 \qecho This is a record attribute reingest of your bib records.
4648 \qecho It will take a while.
4649 \qecho You may cancel now without losing the effect of the rest of the
4650 \qecho upgrade script, and arrange the reingest later.
4651 SELECT COUNT(metabib.reingest_record_attributes(id))
4652     FROM biblio.record_entry WHERE deleted IS FALSE;