main_entry INT REFERENCES authority.control_set_authority_field (id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
control_set INT NOT NULL REFERENCES authority.control_set (id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
tag CHAR(3) NOT NULL,
+ nfi CHAR(1), -- non-filing indicator
sf_list TEXT NOT NULL,
name TEXT NOT NULL, -- i18n
description TEXT -- i18n
DECLARE
acsaf authority.control_set_authority_field%ROWTYPE;
tag_used TEXT;
+ nfi_used TEXT;
sf TEXT;
thes_code TEXT;
cset INT;
heading_text TEXT;
tmp_text TEXT;
+ first_sf BOOL;
+ auth_id INT DEFAULT oils_xpath_string('//*[@tag="901"]/*[local-name()="subfield" and @code="c"]', marcxml)::INT;
BEGIN
- thes_code := vandelay.marc21_extract_fixed_field(marcxml,'Subj');
- IF thes_code IS NULL THEN
- thes_code := '|';
+ SELECT control_set INTO cset FROM authority.record_entry WHERE id = auth_id;
+
+ IF cset IS NULL THEN
+ SELECT control_set INTO cset
+ FROM authority.control_set_authority_field
+ WHERE tag IN ( SELECT UNNEST(XPATH('//*[starts-with(@tag,"1")]/@tag',marcxml::XML)::TEXT[]))
+ LIMIT 1;
END IF;
- SELECT control_set INTO cset FROM authority.thesaurus WHERE code = thes_code;
- IF NOT FOUND THEN
- cset = 1;
+ IF thes_code = 'z' THEN
+ thes_code := COALESCE( oils_xpath_string('//*[@tag="040"]/*[@code="f"][1]', marcxml), '' );
END IF;
heading_text := '';
FOR acsaf IN SELECT * FROM authority.control_set_authority_field WHERE control_set = cset AND main_entry IS NULL LOOP
tag_used := acsaf.tag;
+ nfi_used := acsaf.nfi;
+ first_sf := TRUE;
FOR sf IN SELECT * FROM regexp_split_to_table(acsaf.sf_list,'') LOOP
tmp_text := oils_xpath_string('//*[@tag="'||tag_used||'"]/*[@code="'||sf||'"]', marcxml);
+
+ IF first_sf AND tmp_text IS NOT NULL AND nfi_used IS NOT NULL THEN
+
+ tmp_text := SUBSTRING(
+ tmp_text FROM
+ COALESCE(
+ NULLIF(
+ REGEXP_REPLACE(
+ oils_xpath_string('//*[@tag="'||tag_used||'"]/@ind'||nfi_used, marcxml),
+ $$\D+$$,
+ '',
+ 'g'
+ ),
+ ''
+ )::INT,
+ 0
+ ) + 1
+ );
+
+ END IF;
+
+ first_sf := FALSE;
+
IF tmp_text IS NOT NULL AND tmp_text <> '' THEN
heading_text := heading_text || E'\u2021' || sf || ' ' || tmp_text;
END IF;
EXIT WHEN heading_text <> '';
END LOOP;
- IF thes_code = 'z' THEN
- thes_code := oils_xpath_string('//*[@tag="040"]/*[@code="f"][1]', marcxml);
- END IF;
-
IF heading_text <> '' THEN
IF no_thesaurus IS TRUE THEN
heading_text := tag_used || ' ' || public.naco_normalize(heading_text);
ELSE
- heading_text := tag_used || '_' || thes_code || ' ' || public.naco_normalize(heading_text);
+ heading_text := tag_used || '_' || COALESCE(nfi_used,'-') || '_' || thes_code || ' ' || public.naco_normalize(heading_text);
END IF;
ELSE
heading_text := 'NOHEADING_' || thes_code || ' ' || MD5(marcxml);
END;
$func$ LANGUAGE PLPGSQL IMMUTABLE;
+CREATE TABLE authority.simple_heading (
+ id BIGSERIAL PRIMARY KEY,
+ record BIGINT NOT NULL REFERENCES authority.record_entry (id),
+ atag INT NOT NULL REFERENCES authority.control_set_authority_field (id),
+ value TEXT NOT NULL,
+ index_vector tsvector NOT NULL
+);
+CREATE TRIGGER authority_simple_heading_fti_trigger
+ BEFORE UPDATE OR INSERT ON authority.simple_heading
+ FOR EACH ROW EXECUTE PROCEDURE tsearch2(index_vector, value);
+
+CREATE INDEX authority_simple_heading_index_vector_idx ON authority.full_rec USING GIST (index_vector);
+CREATE INDEX authority_simple_heading_value_idx ON authority.simple_heading (value);
+
+CREATE OR REPLACE FUNCTION authority.simple_heading_set( marcxml TEXT ) RETURNS SETOF authority.simple_heading AS $func$
+DECLARE
+ res authority.simple_heading%ROWTYPE;
+ acsaf authority.control_set_authority_field%ROWTYPE;
+ tag_used TEXT;
+ nfi_used TEXT;
+ sf TEXT;
+ cset INT;
+ heading_text TEXT;
+ tmp_text TEXT;
+ tmp_xml TEXT;
+ first_sf BOOL;
+ auth_id INT DEFAULT oils_xpath_string('//*[@tag="901"]/*[local-name()="subfield" and @code="c"]', marcxml)::INT;
+BEGIN
+
+ res.record := auth_id;
+
+ SELECT control_set INTO cset
+ FROM authority.control_set_authority_field
+ WHERE tag IN ( SELECT UNNEST(XPATH('//*[starts-with(@tag,"1")]/@tag',marcxml::XML)::TEXT[]) )
+ LIMIT 1;
+
+ FOR acsaf IN SELECT * FROM authority.control_set_authority_field WHERE control_set = cset LOOP
+
+ res.atag := acsaf.id;
+ tag_used := acsaf.tag;
+ nfi_used := acsaf.nfi;
+
+ FOR tmp_xml IN SELECT UNNEST(XPATH('//*[@tag="'||tag_used||'"]', marcxml::XML)) LOOP
+ heading_text := '';
+
+ FOR sf IN SELECT * FROM regexp_split_to_table(acsaf.sf_list,'') LOOP
+ heading_text := heading_text || COALESCE( ' ' || oils_xpath_string('//*[@code="'||sf||'"]',tmp_xml::TEXT), '');
+ END LOOP;
+
+ IF nfi_used IS NOT NULL THEN
+
+ heading_text := SUBSTRING(
+ heading_text FROM
+ COALESCE(
+ NULLIF(
+ REGEXP_REPLACE(
+ oils_xpath_string('//*[@tag="'||tag_used||'"]/@ind'||nfi_used, marcxml),
+ $$\D+$$,
+ '',
+ 'g'
+ ),
+ ''
+ )::INT,
+ 0
+ ) + 1
+ );
+
+ END IF;
+
+ IF heading_text IS NOT NULL AND heading_text <> '' THEN
+ res.value := public.naco_normalize( BTRIM(heading_text) );
+ RETURN NEXT res;
+ END IF;
+
+ END LOOP;
+
+ END LOOP;
+
+ RETURN;
+END;
+$func$ LANGUAGE PLPGSQL IMMUTABLE;
+
CREATE OR REPLACE FUNCTION authority.simple_normalize_heading( marcxml TEXT ) RETURNS TEXT AS $func$
SELECT authority.normalize_heading($1, TRUE);
$func$ LANGUAGE SQL IMMUTABLE;
thesaurus.
$$;
+
-- Adding indexes using oils_xpath_string() for the main entry tags described in
-- authority.control_set_authority_field would speed this up, if we ever want to use it, though
-- the existing index on authority.normalize_heading() helps already with a record in hand
IF NEW.deleted IS TRUE THEN -- If this authority is deleted
DELETE FROM authority.bib_linking WHERE authority = NEW.id; -- Avoid updating fields in bibs that are no longer visible
DELETE FROM authority.full_rec WHERE record = NEW.id; -- Avoid validating fields against deleted authority records
+ DELETE FROM authority.simple_heading WHERE record = NEW.id;
-- Should remove matching $0 from controlled fields at the same time?
RETURN NEW; -- and we're done
END IF;
IF NOT FOUND AND OLD.marc = NEW.marc THEN -- don't do anything if the MARC didn't change
RETURN NEW;
END IF;
+
-- Propagate these updates to any linked bib records
PERFORM authority.propagate_changes(NEW.id) FROM authority.record_entry WHERE id = NEW.id;
+
+ DELETE FROM authority.simple_heading WHERE record = NEW.id;
END IF;
+ INSERT INTO authority.simple_heading (record,atag,value)
+ SELECT record, atag, value FROM authority.simple_heading_set(NEW.marc);
+
-- Flatten and insert the afr data
PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_authority_full_rec' AND enabled;
IF NOT FOUND THEN