3 SELECT evergreen.upgrade_deps_block_check('0985', :eg_version);
5 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$
12 xfrm config.xml_transform%ROWTYPE;
13 attr_vector INT[] := '{}'::INT[];
14 attr_vector_tmp INT[];
15 attr_list TEXT[] := pattr_list;
17 norm_attr_value TEXT[];
19 attr_def config.record_attr_definition%ROWTYPE;
20 ccvm_row config.coded_value_map%ROWTYPE;
23 IF attr_list IS NULL OR rdeleted THEN -- need to do the full dance on INSERT or undelete
24 SELECT ARRAY_AGG(name) INTO attr_list FROM config.record_attr_definition
27 fixed_field IS NOT NULL OR
29 phys_char_sf IS NOT NULL OR
37 SELECT marc INTO rmarc FROM biblio.record_entry WHERE id = rid;
40 FOR attr_def IN SELECT * FROM config.record_attr_definition WHERE NOT composite AND name = ANY( attr_list ) ORDER BY format LOOP
42 attr_value := '{}'::TEXT[];
43 norm_attr_value := '{}'::TEXT[];
44 attr_vector_tmp := '{}'::INT[];
46 SELECT * INTO ccvm_row FROM config.coded_value_map c WHERE c.ctype = attr_def.name LIMIT 1;
48 -- tag+sf attrs only support SVF
49 IF attr_def.tag IS NOT NULL THEN -- tag (and optional subfield list) selection
50 SELECT ARRAY[ARRAY_TO_STRING(ARRAY_AGG(value), COALESCE(attr_def.joiner,' '))] INTO attr_value
51 FROM (SELECT * FROM metabib.full_rec ORDER BY tag, subfield) AS x
53 AND tag LIKE attr_def.tag
55 WHEN attr_def.sf_list IS NOT NULL
56 THEN POSITION(subfield IN attr_def.sf_list) > 0
63 ELSIF attr_def.fixed_field IS NOT NULL THEN -- a named fixed field, see config.marc21_ff_pos_map.fixed_field
64 attr_value := vandelay.marc21_extract_fixed_field_list(rmarc, attr_def.fixed_field);
66 IF NOT attr_def.multi THEN
67 attr_value := ARRAY[attr_value[1]];
70 ELSIF attr_def.xpath IS NOT NULL THEN -- and xpath expression
72 SELECT INTO xfrm * FROM config.xml_transform WHERE name = attr_def.format;
74 -- See if we can skip the XSLT ... it's expensive
75 IF prev_xfrm IS NULL OR prev_xfrm <> xfrm.name THEN
76 -- Can't skip the transform
77 IF xfrm.xslt <> '---' THEN
78 transformed_xml := oils_xslt_process(rmarc,xfrm.xslt);
80 transformed_xml := rmarc;
83 prev_xfrm := xfrm.name;
86 IF xfrm.name IS NULL THEN
87 -- just grab the marcxml (empty) transform
88 SELECT INTO xfrm * FROM config.xml_transform WHERE xslt = '---' LIMIT 1;
89 prev_xfrm := xfrm.name;
92 FOR tmp_xml IN SELECT UNNEST(oils_xpath(attr_def.xpath, transformed_xml, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]])) LOOP
93 tmp_val := oils_xpath_string(
96 COALESCE(attr_def.joiner,' '),
97 ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]]
99 IF tmp_val IS NOT NULL AND BTRIM(tmp_val) <> '' THEN
100 attr_value := attr_value || tmp_val;
101 EXIT WHEN NOT attr_def.multi;
105 ELSIF attr_def.phys_char_sf IS NOT NULL THEN -- a named Physical Characteristic, see config.marc21_physical_characteristic_*_map
106 SELECT ARRAY_AGG(m.value) INTO attr_value
107 FROM vandelay.marc21_physical_characteristics(rmarc) v
108 LEFT JOIN config.marc21_physical_characteristic_value_map m ON (m.id = v.value)
109 WHERE v.subfield = attr_def.phys_char_sf AND (m.value IS NOT NULL AND BTRIM(m.value) <> '')
110 AND ( ccvm_row.id IS NULL OR ( ccvm_row.id IS NOT NULL AND v.id IS NOT NULL) );
112 IF NOT attr_def.multi THEN
113 attr_value := ARRAY[attr_value[1]];
118 -- apply index normalizers to attr_value
119 FOR tmp_val IN SELECT value FROM UNNEST(attr_value) x(value) LOOP
121 SELECT n.func AS func,
122 n.param_count AS param_count,
124 FROM config.index_normalizer n
125 JOIN config.record_attr_index_norm_map m ON (m.norm = n.id)
126 WHERE attr = attr_def.name
128 EXECUTE 'SELECT ' || normalizer.func || '(' ||
129 COALESCE( quote_literal( tmp_val ), 'NULL' ) ||
131 WHEN normalizer.param_count > 0
132 THEN ',' || REPLACE(REPLACE(BTRIM(normalizer.params,'[]'),E'\'',E'\\\''),E'"',E'\'')
138 IF tmp_val IS NOT NULL AND tmp_val <> '' THEN
139 -- note that a string that contains only blanks
140 -- is a valid value for some attributes
141 norm_attr_value := norm_attr_value || tmp_val;
145 IF attr_def.filter THEN
146 -- Create unknown uncontrolled values and find the IDs of the values
147 IF ccvm_row.id IS NULL THEN
148 FOR tmp_val IN SELECT value FROM UNNEST(norm_attr_value) x(value) LOOP
149 IF tmp_val IS NOT NULL AND BTRIM(tmp_val) <> '' THEN
150 BEGIN -- use subtransaction to isolate unique constraint violations
151 INSERT INTO metabib.uncontrolled_record_attr_value ( attr, value ) VALUES ( attr_def.name, tmp_val );
152 EXCEPTION WHEN unique_violation THEN END;
156 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 );
158 SELECT ARRAY_AGG(id) INTO attr_vector_tmp FROM config.coded_value_map WHERE ctype = attr_def.name AND code = ANY( norm_attr_value );
161 -- Add the new value to the vector
162 attr_vector := attr_vector || attr_vector_tmp;
165 IF attr_def.sorter THEN
166 DELETE FROM metabib.record_sorter WHERE source = rid AND attr = attr_def.name;
167 IF norm_attr_value[1] IS NOT NULL THEN
168 INSERT INTO metabib.record_sorter (source, attr, value) VALUES (rid, attr_def.name, norm_attr_value[1]);
174 /* We may need to rewrite the vlist to contain
175 the intersection of new values for requested
176 attrs and old values for ignored attrs. To
177 do this, we take the old attr vlist and
178 subtract any values that are valid for the
179 requested attrs, and then add back the new
180 set of attr values. */
182 IF ARRAY_LENGTH(pattr_list, 1) > 0 THEN
183 SELECT vlist INTO attr_vector_tmp FROM metabib.record_attr_vector_list WHERE source = rid;
184 SELECT attr_vector_tmp - ARRAY_AGG(id::INT) INTO attr_vector_tmp FROM metabib.full_attr_id_map WHERE attr = ANY (pattr_list);
185 attr_vector := attr_vector || attr_vector_tmp;
188 -- On to composite attributes, now that the record attrs have been pulled. Processed in name order, so later composite
189 -- attributes can depend on earlier ones.
190 PERFORM metabib.compile_composite_attr_cache_init();
191 FOR attr_def IN SELECT * FROM config.record_attr_definition WHERE composite AND name = ANY( attr_list ) ORDER BY name LOOP
193 FOR ccvm_row IN SELECT * FROM config.coded_value_map c WHERE c.ctype = attr_def.name ORDER BY value LOOP
195 tmp_val := metabib.compile_composite_attr( ccvm_row.id );
196 CONTINUE WHEN tmp_val IS NULL OR tmp_val = ''; -- nothing to do
198 IF attr_def.filter THEN
199 IF attr_vector @@ tmp_val::query_int THEN
200 attr_vector = attr_vector + intset(ccvm_row.id);
201 EXIT WHEN NOT attr_def.multi;
205 IF attr_def.sorter THEN
206 IF attr_vector @@ tmp_val THEN
207 DELETE FROM metabib.record_sorter WHERE source = rid AND attr = attr_def.name;
208 INSERT INTO metabib.record_sorter (source, attr, value) VALUES (rid, attr_def.name, ccvm_row.code);
216 IF ARRAY_LENGTH(attr_vector, 1) > 0 THEN
217 IF rdeleted THEN -- initial insert OR revivication
218 DELETE FROM metabib.record_attr_vector_list WHERE source = rid;
219 INSERT INTO metabib.record_attr_vector_list (source, vlist) VALUES (rid, attr_vector);
221 UPDATE metabib.record_attr_vector_list SET vlist = attr_vector WHERE source = rid;
227 $func$ LANGUAGE PLPGSQL;
229 CREATE INDEX config_coded_value_map_ctype_idx ON config.coded_value_map (ctype);