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