LP1284864 - stamping upgrade for deleted metarecord function fixing
authorBen Shum <bshum@biblio.org>
Mon, 10 Mar 2014 16:55:04 +0000 (12:55 -0400)
committerBen Shum <bshum@biblio.org>
Mon, 10 Mar 2014 16:55:04 +0000 (12:55 -0400)
Signed-off-by: Ben Shum <bshum@biblio.org>
Open-ILS/src/sql/Pg/002.schema.config.sql
Open-ILS/src/sql/Pg/upgrade/0872.functions.metarecord-deleted-constituents.sql [new file with mode: 0644]
Open-ILS/src/sql/Pg/upgrade/XXXX.functions.metarecord-deleted-constituents.sql [deleted file]

index dfcbbcd..688d9b0 100644 (file)
@@ -91,7 +91,7 @@ CREATE TRIGGER no_overlapping_deps
     BEFORE INSERT OR UPDATE ON config.db_patch_dependencies
     FOR EACH ROW EXECUTE PROCEDURE evergreen.array_overlap_check ('deprecates');
 
-INSERT INTO config.upgrade_log (version, applied_to) VALUES ('0871', :eg_version); -- berick/miker
+INSERT INTO config.upgrade_log (version, applied_to) VALUES ('0872', :eg_version); -- miker/bshum
 
 CREATE TABLE config.bib_source (
        id              SERIAL  PRIMARY KEY,
diff --git a/Open-ILS/src/sql/Pg/upgrade/0872.functions.metarecord-deleted-constituents.sql b/Open-ILS/src/sql/Pg/upgrade/0872.functions.metarecord-deleted-constituents.sql
new file mode 100644 (file)
index 0000000..b32c4b2
--- /dev/null
@@ -0,0 +1,355 @@
+BEGIN;
+
+SELECT evergreen.upgrade_deps_block_check('0872', :eg_version);
+
+CREATE OR REPLACE FUNCTION metabib.remap_metarecord_for_bib( bib_id BIGINT, fp TEXT, bib_is_deleted BOOL DEFAULT FALSE, retain_deleted BOOL DEFAULT FALSE ) RETURNS BIGINT AS $func$
+DECLARE
+    new_mapping     BOOL := TRUE;
+    source_count    INT;
+    old_mr          BIGINT;
+    tmp_mr          metabib.metarecord%ROWTYPE;
+    deleted_mrs     BIGINT[];
+BEGIN
+
+    -- We need to make sure we're not a deleted master record of an MR
+    IF bib_is_deleted THEN
+        FOR old_mr IN SELECT id FROM metabib.metarecord WHERE master_record = bib_id LOOP
+
+            IF NOT retain_deleted THEN -- Go away for any MR that we're master of, unless retained
+                DELETE FROM metabib.metarecord_source_map WHERE source = bib_id;
+            END IF;
+
+            -- Now, are there any more sources on this MR?
+            SELECT COUNT(*) INTO source_count FROM metabib.metarecord_source_map WHERE metarecord = old_mr;
+
+            IF source_count = 0 AND NOT retain_deleted THEN -- No other records
+                deleted_mrs := ARRAY_APPEND(deleted_mrs, old_mr); -- Just in case...
+                DELETE FROM metabib.metarecord WHERE id = old_mr;
+
+            ELSE -- indeed there are. Update it with a null cache and recalcualated master record
+                UPDATE  metabib.metarecord
+                  SET   mods = NULL,
+                        master_record = ( SELECT id FROM biblio.record_entry WHERE fingerprint = fp AND NOT deleted ORDER BY quality DESC LIMIT 1)
+                  WHERE id = old_mr;
+            END IF;
+        END LOOP;
+
+    ELSE -- insert or update
+
+        FOR tmp_mr IN SELECT m.* FROM metabib.metarecord m JOIN metabib.metarecord_source_map s ON (s.metarecord = m.id) WHERE s.source = bib_id LOOP
+
+            -- Find the first fingerprint-matching
+            IF old_mr IS NULL AND fp = tmp_mr.fingerprint THEN
+                old_mr := tmp_mr.id;
+                new_mapping := FALSE;
+
+            ELSE -- Our fingerprint changed ... maybe remove the old MR
+                DELETE FROM metabib.metarecord_source_map WHERE metarecord = old_mr AND source = bib_id; -- remove the old source mapping
+                SELECT COUNT(*) INTO source_count FROM metabib.metarecord_source_map WHERE metarecord = tmp_mr.id;
+                IF source_count = 0 THEN -- No other records
+                    deleted_mrs := ARRAY_APPEND(deleted_mrs, tmp_mr.id);
+                    DELETE FROM metabib.metarecord WHERE id = tmp_mr.id;
+                END IF;
+            END IF;
+
+        END LOOP;
+
+        -- we found no suitable, preexisting MR based on old source maps
+        IF old_mr IS NULL THEN
+            SELECT id INTO old_mr FROM metabib.metarecord WHERE fingerprint = fp; -- is there one for our current fingerprint?
+
+            IF old_mr IS NULL THEN -- nope, create one and grab its id
+                INSERT INTO metabib.metarecord ( fingerprint, master_record ) VALUES ( fp, bib_id );
+                SELECT id INTO old_mr FROM metabib.metarecord WHERE fingerprint = fp;
+
+            ELSE -- indeed there is. update it with a null cache and recalcualated master record
+                UPDATE  metabib.metarecord
+                  SET   mods = NULL,
+                        master_record = ( SELECT id FROM biblio.record_entry WHERE fingerprint = fp AND NOT deleted ORDER BY quality DESC LIMIT 1)
+                  WHERE id = old_mr;
+            END IF;
+
+        ELSE -- there was one we already attached to, update its mods cache and master_record
+            UPDATE  metabib.metarecord
+              SET   mods = NULL,
+                    master_record = ( SELECT id FROM biblio.record_entry WHERE fingerprint = fp AND NOT deleted ORDER BY quality DESC LIMIT 1)
+              WHERE id = old_mr;
+        END IF;
+
+        IF new_mapping THEN
+            INSERT INTO metabib.metarecord_source_map (metarecord, source) VALUES (old_mr, bib_id); -- new source mapping
+        END IF;
+
+    END IF;
+
+    IF ARRAY_UPPER(deleted_mrs,1) > 0 THEN
+        UPDATE action.hold_request SET target = old_mr WHERE target IN ( SELECT unnest(deleted_mrs) ) AND hold_type = 'M'; -- if we had to delete any MRs above, make sure their holds are moved
+    END IF;
+
+    RETURN old_mr;
+
+END;
+$func$ LANGUAGE PLPGSQL;
+
+DROP FUNCTION metabib.remap_metarecord_for_bib( bib_id BIGINT, fp TEXT );
+
+CREATE OR REPLACE FUNCTION biblio.indexing_ingest_or_delete () RETURNS TRIGGER AS $func$
+DECLARE
+    tmp_bool BOOL;
+BEGIN
+
+    IF NEW.deleted THEN -- If this bib is deleted
+
+        PERFORM * FROM config.internal_flag WHERE
+            name = 'ingest.metarecord_mapping.preserve_on_delete' AND enabled;
+
+        tmp_bool := FOUND; -- Just in case this is changed by some other statement
+
+        PERFORM metabib.remap_metarecord_for_bib( NEW.id, NEW.fingerprint, TRUE, tmp_bool );
+
+        IF NOT tmp_bool THEN
+            -- One needs to keep these around to support searches
+            -- with the #deleted modifier, so one should turn on the named
+            -- internal flag for that functionality.
+            DELETE FROM metabib.record_attr_vector_list WHERE source = NEW.id;
+        END IF;
+
+        DELETE FROM authority.bib_linking WHERE bib = NEW.id; -- Avoid updating fields in bibs that are no longer visible
+        DELETE FROM biblio.peer_bib_copy_map WHERE peer_record = NEW.id; -- Separate any multi-homed items
+        DELETE FROM metabib.browse_entry_def_map WHERE source = NEW.id; -- Don't auto-suggest deleted bibs
+        RETURN NEW; -- and we're done
+    END IF;
+
+    IF TG_OP = 'UPDATE' THEN -- re-ingest?
+        PERFORM * FROM config.internal_flag WHERE name = 'ingest.reingest.force_on_same_marc' AND enabled;
+
+        IF NOT FOUND AND OLD.marc = NEW.marc THEN -- don't do anything if the MARC didn't change
+            RETURN NEW;
+        END IF;
+    END IF;
+
+    -- Record authority linking
+    PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_authority_linking' AND enabled;
+    IF NOT FOUND THEN
+        PERFORM biblio.map_authority_linking( NEW.id, NEW.marc );
+    END IF;
+
+    -- Flatten and insert the mfr data
+    PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_metabib_full_rec' AND enabled;
+    IF NOT FOUND THEN
+        PERFORM metabib.reingest_metabib_full_rec(NEW.id);
+
+        -- Now we pull out attribute data, which is dependent on the mfr for all but XPath-based fields
+        PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_metabib_rec_descriptor' AND enabled;
+        IF NOT FOUND THEN
+            PERFORM metabib.reingest_record_attributes(NEW.id, NULL, NEW.marc, TG_OP = 'INSERT' OR OLD.deleted);
+        END IF;
+    END IF;
+
+    -- Gather and insert the field entry data
+    PERFORM metabib.reingest_metabib_field_entries(NEW.id);
+
+    -- Located URI magic
+    IF TG_OP = 'INSERT' THEN
+        PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_located_uri' AND enabled;
+        IF NOT FOUND THEN
+            PERFORM biblio.extract_located_uris( NEW.id, NEW.marc, NEW.editor );
+        END IF;
+    ELSE
+        PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_located_uri' AND enabled;
+        IF NOT FOUND THEN
+            PERFORM biblio.extract_located_uris( NEW.id, NEW.marc, NEW.editor );
+        END IF;
+    END IF;
+
+    -- (re)map metarecord-bib linking
+    IF TG_OP = 'INSERT' THEN -- if not deleted and performing an insert, check for the flag
+        PERFORM * FROM config.internal_flag WHERE name = 'ingest.metarecord_mapping.skip_on_insert' AND enabled;
+        IF NOT FOUND THEN
+            PERFORM metabib.remap_metarecord_for_bib( NEW.id, NEW.fingerprint );
+        END IF;
+    ELSE -- we're doing an update, and we're not deleted, remap
+        PERFORM * FROM config.internal_flag WHERE name = 'ingest.metarecord_mapping.skip_on_update' AND enabled;
+        IF NOT FOUND THEN
+            PERFORM metabib.remap_metarecord_for_bib( NEW.id, NEW.fingerprint );
+        END IF;
+    END IF;
+
+    RETURN NEW;
+END;
+$func$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION unapi.mmr (
+    obj_id BIGINT,
+    format TEXT,
+    ename TEXT,
+    includes TEXT[],
+    org TEXT,
+    depth INT DEFAULT NULL,
+    slimit HSTORE DEFAULT NULL,
+    soffset HSTORE DEFAULT NULL,
+    include_xmlns BOOL DEFAULT TRUE,
+    pref_lib INT DEFAULT NULL
+)
+RETURNS XML AS $F$
+DECLARE
+    mmrec   metabib.metarecord%ROWTYPE;
+    leadrec biblio.record_entry%ROWTYPE;
+    subrec biblio.record_entry%ROWTYPE;
+    layout  unapi.bre_output_layout%ROWTYPE;
+    xfrm    config.xml_transform%ROWTYPE;
+    ouid    INT;
+    xml_buf TEXT; -- growing XML document
+    tmp_xml TEXT; -- single-use XML string
+    xml_frag TEXT; -- single-use XML fragment
+    top_el  TEXT;
+    output  XML;
+    hxml    XML;
+    axml    XML;
+    subxml  XML; -- subordinate records elements
+    sub_xpath TEXT; 
+    parts   TEXT[]; 
+BEGIN
+
+    -- xpath for extracting bre.marc values from subordinate records 
+    -- so they may be appended to the MARC of the master record prior
+    -- to XSLT processing.
+    -- subjects, isbn, issn, upc -- anything else?
+    sub_xpath := 
+      '//*[starts-with(@tag, "6") or @tag="020" or @tag="022" or @tag="024"]';
+
+    IF org = '-' OR org IS NULL THEN
+        SELECT shortname INTO org FROM evergreen.org_top();
+    END IF;
+
+    SELECT id INTO ouid FROM actor.org_unit WHERE shortname = org;
+
+    IF ouid IS NULL THEN
+        RETURN NULL::XML;
+    END IF;
+
+    SELECT INTO mmrec * FROM metabib.metarecord WHERE id = obj_id;
+    IF NOT FOUND THEN
+        RETURN NULL::XML;
+    END IF;
+
+    -- TODO: aggregate holdings from constituent records
+    IF format = 'holdings_xml' THEN -- the special case
+        output := unapi.mmr_holdings_xml(
+            obj_id, ouid, org, depth,
+            evergreen.array_remove_item_by_value(includes,'holdings_xml'),
+            slimit, soffset, include_xmlns, pref_lib);
+        RETURN output;
+    END IF;
+
+    SELECT * INTO layout FROM unapi.bre_output_layout WHERE name = format;
+
+    IF layout.name IS NULL THEN
+        RETURN NULL::XML;
+    END IF;
+
+    SELECT * INTO xfrm FROM config.xml_transform WHERE name = layout.transform;
+
+    SELECT INTO leadrec * FROM biblio.record_entry WHERE id = mmrec.master_record;
+
+    -- Grab distinct MVF for all records if requested
+    IF ('mra' = ANY (includes)) THEN 
+        axml := unapi.mmr_mra(obj_id,NULL,NULL,NULL,org,depth,NULL,NULL,TRUE,pref_lib);
+    ELSE
+        axml := NULL::XML;
+    END IF;
+
+    xml_buf = leadrec.marc;
+
+    hxml := NULL::XML;
+    IF ('holdings_xml' = ANY (includes)) THEN
+        hxml := unapi.mmr_holdings_xml(
+                    obj_id, ouid, org, depth,
+                    evergreen.array_remove_item_by_value(includes,'holdings_xml'),
+                    slimit, soffset, include_xmlns, pref_lib);
+    END IF;
+
+    subxml := NULL::XML;
+    parts := '{}'::TEXT[];
+    FOR subrec IN SELECT bre.* FROM biblio.record_entry bre
+         JOIN metabib.metarecord_source_map mmsm ON (mmsm.source = bre.id)
+         JOIN metabib.metarecord mmr ON (mmr.id = mmsm.metarecord)
+         WHERE mmr.id = obj_id AND NOT bre.deleted
+         ORDER BY CASE WHEN bre.id = mmr.master_record THEN 0 ELSE bre.id END
+         LIMIT COALESCE((slimit->'bre')::INT, 5) LOOP
+
+        IF subrec.id = leadrec.id THEN CONTINUE; END IF;
+        -- Append choice data from the the non-lead records to the 
+        -- the lead record document
+
+        parts := parts || xpath(sub_xpath, subrec.marc::XML)::TEXT[];
+    END LOOP;
+
+    SELECT ARRAY_TO_STRING( ARRAY_AGG( DISTINCT p ), '' )::XML INTO subxml FROM UNNEST(parts) p;
+
+    -- append data from the subordinate records to the 
+    -- main record document before applying the XSLT
+
+    IF subxml IS NOT NULL THEN 
+        xml_buf := REGEXP_REPLACE(xml_buf, 
+            '</record>(.*?)$', subxml || '</record>' || E'\\1');
+    END IF;
+
+    IF format = 'marcxml' THEN
+         -- If we're not using the prefixed namespace in 
+         -- this record, then remove all declarations of it
+        IF xml_buf !~ E'<marc:' THEN
+           xml_buf := REGEXP_REPLACE(xml_buf, 
+            ' xmlns:marc="http://www.loc.gov/MARC21/slim"', '', 'g');
+        END IF; 
+    ELSE
+        xml_buf := oils_xslt_process(xml_buf, xfrm.xslt)::XML;
+    END IF;
+
+    -- update top_el to reflect the change in xml_buf, which may
+    -- now be a different type of document (e.g. record -> mods)
+    top_el := REGEXP_REPLACE(xml_buf, E'^.*?<((?:\\S+:)?' || 
+        layout.holdings_element || ').*$', E'\\1');
+
+    IF axml IS NOT NULL THEN 
+        xml_buf := REGEXP_REPLACE(xml_buf, 
+            '</' || top_el || '>(.*?)$', axml || '</' || top_el || E'>\\1');
+    END IF;
+
+    IF hxml IS NOT NULL THEN
+        xml_buf := REGEXP_REPLACE(xml_buf, 
+            '</' || top_el || '>(.*?)$', hxml || '</' || top_el || E'>\\1');
+    END IF;
+
+    IF ('mmr.unapi' = ANY (includes)) THEN 
+        output := REGEXP_REPLACE(
+            xml_buf,
+            '</' || top_el || '>(.*?)',
+            XMLELEMENT(
+                name abbr,
+                XMLATTRIBUTES(
+                    'http://www.w3.org/1999/xhtml' AS xmlns,
+                    'unapi-id' AS class,
+                    'tag:open-ils.org:U2@mmr/' || obj_id || '/' || org AS title
+                )
+            )::TEXT || '</' || top_el || E'>\\1'
+        );
+    ELSE
+        output := xml_buf;
+    END IF;
+
+    -- remove ignorable whitesace
+    output := REGEXP_REPLACE(output::TEXT,E'>\\s+<','><','gs')::XML;
+    RETURN output;
+END;
+$F$ LANGUAGE PLPGSQL STABLE;
+
+-- Forcibly remap deleted master records, retaining the linkage if so configured.
+SELECT  metabib.remap_metarecord_for_bib( bre.id, bre.fingerprint, TRUE, COALESCE(flag.enabled,FALSE))
+  FROM  metabib.metarecord metar
+        JOIN biblio.record_entry bre ON bre.id = metar.master_record,
+        config.internal_flag flag
+  WHERE bre.deleted = TRUE AND flag.name = 'ingest.metarecord_mapping.preserve_on_delete';
+
+COMMIT;
+
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.functions.metarecord-deleted-constituents.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.functions.metarecord-deleted-constituents.sql
deleted file mode 100644 (file)
index ab23ff5..0000000
+++ /dev/null
@@ -1,355 +0,0 @@
-BEGIN;
-
-SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version);
-
-CREATE OR REPLACE FUNCTION metabib.remap_metarecord_for_bib( bib_id BIGINT, fp TEXT, bib_is_deleted BOOL DEFAULT FALSE, retain_deleted BOOL DEFAULT FALSE ) RETURNS BIGINT AS $func$
-DECLARE
-    new_mapping     BOOL := TRUE;
-    source_count    INT;
-    old_mr          BIGINT;
-    tmp_mr          metabib.metarecord%ROWTYPE;
-    deleted_mrs     BIGINT[];
-BEGIN
-
-    -- We need to make sure we're not a deleted master record of an MR
-    IF bib_is_deleted THEN
-        FOR old_mr IN SELECT id FROM metabib.metarecord WHERE master_record = bib_id LOOP
-
-            IF NOT retain_deleted THEN -- Go away for any MR that we're master of, unless retained
-                DELETE FROM metabib.metarecord_source_map WHERE source = bib_id;
-            END IF;
-
-            -- Now, are there any more sources on this MR?
-            SELECT COUNT(*) INTO source_count FROM metabib.metarecord_source_map WHERE metarecord = old_mr;
-
-            IF source_count = 0 AND NOT retain_deleted THEN -- No other records
-                deleted_mrs := ARRAY_APPEND(deleted_mrs, old_mr); -- Just in case...
-                DELETE FROM metabib.metarecord WHERE id = old_mr;
-
-            ELSE -- indeed there are. Update it with a null cache and recalcualated master record
-                UPDATE  metabib.metarecord
-                  SET   mods = NULL,
-                        master_record = ( SELECT id FROM biblio.record_entry WHERE fingerprint = fp AND NOT deleted ORDER BY quality DESC LIMIT 1)
-                  WHERE id = old_mr;
-            END IF;
-        END LOOP;
-
-    ELSE -- insert or update
-
-        FOR tmp_mr IN SELECT m.* FROM metabib.metarecord m JOIN metabib.metarecord_source_map s ON (s.metarecord = m.id) WHERE s.source = bib_id LOOP
-
-            -- Find the first fingerprint-matching
-            IF old_mr IS NULL AND fp = tmp_mr.fingerprint THEN
-                old_mr := tmp_mr.id;
-                new_mapping := FALSE;
-
-            ELSE -- Our fingerprint changed ... maybe remove the old MR
-                DELETE FROM metabib.metarecord_source_map WHERE metarecord = old_mr AND source = bib_id; -- remove the old source mapping
-                SELECT COUNT(*) INTO source_count FROM metabib.metarecord_source_map WHERE metarecord = tmp_mr.id;
-                IF source_count = 0 THEN -- No other records
-                    deleted_mrs := ARRAY_APPEND(deleted_mrs, tmp_mr.id);
-                    DELETE FROM metabib.metarecord WHERE id = tmp_mr.id;
-                END IF;
-            END IF;
-
-        END LOOP;
-
-        -- we found no suitable, preexisting MR based on old source maps
-        IF old_mr IS NULL THEN
-            SELECT id INTO old_mr FROM metabib.metarecord WHERE fingerprint = fp; -- is there one for our current fingerprint?
-
-            IF old_mr IS NULL THEN -- nope, create one and grab its id
-                INSERT INTO metabib.metarecord ( fingerprint, master_record ) VALUES ( fp, bib_id );
-                SELECT id INTO old_mr FROM metabib.metarecord WHERE fingerprint = fp;
-
-            ELSE -- indeed there is. update it with a null cache and recalcualated master record
-                UPDATE  metabib.metarecord
-                  SET   mods = NULL,
-                        master_record = ( SELECT id FROM biblio.record_entry WHERE fingerprint = fp AND NOT deleted ORDER BY quality DESC LIMIT 1)
-                  WHERE id = old_mr;
-            END IF;
-
-        ELSE -- there was one we already attached to, update its mods cache and master_record
-            UPDATE  metabib.metarecord
-              SET   mods = NULL,
-                    master_record = ( SELECT id FROM biblio.record_entry WHERE fingerprint = fp AND NOT deleted ORDER BY quality DESC LIMIT 1)
-              WHERE id = old_mr;
-        END IF;
-
-        IF new_mapping THEN
-            INSERT INTO metabib.metarecord_source_map (metarecord, source) VALUES (old_mr, bib_id); -- new source mapping
-        END IF;
-
-    END IF;
-
-    IF ARRAY_UPPER(deleted_mrs,1) > 0 THEN
-        UPDATE action.hold_request SET target = old_mr WHERE target IN ( SELECT unnest(deleted_mrs) ) AND hold_type = 'M'; -- if we had to delete any MRs above, make sure their holds are moved
-    END IF;
-
-    RETURN old_mr;
-
-END;
-$func$ LANGUAGE PLPGSQL;
-
-DROP FUNCTION metabib.remap_metarecord_for_bib( bib_id BIGINT, fp TEXT );
-
-CREATE OR REPLACE FUNCTION biblio.indexing_ingest_or_delete () RETURNS TRIGGER AS $func$
-DECLARE
-    tmp_bool BOOL;
-BEGIN
-
-    IF NEW.deleted THEN -- If this bib is deleted
-
-        PERFORM * FROM config.internal_flag WHERE
-            name = 'ingest.metarecord_mapping.preserve_on_delete' AND enabled;
-
-        tmp_bool := FOUND; -- Just in case this is changed by some other statement
-
-        PERFORM metabib.remap_metarecord_for_bib( NEW.id, NEW.fingerprint, TRUE, tmp_bool );
-
-        IF NOT tmp_bool THEN
-            -- One needs to keep these around to support searches
-            -- with the #deleted modifier, so one should turn on the named
-            -- internal flag for that functionality.
-            DELETE FROM metabib.record_attr_vector_list WHERE source = NEW.id;
-        END IF;
-
-        DELETE FROM authority.bib_linking WHERE bib = NEW.id; -- Avoid updating fields in bibs that are no longer visible
-        DELETE FROM biblio.peer_bib_copy_map WHERE peer_record = NEW.id; -- Separate any multi-homed items
-        DELETE FROM metabib.browse_entry_def_map WHERE source = NEW.id; -- Don't auto-suggest deleted bibs
-        RETURN NEW; -- and we're done
-    END IF;
-
-    IF TG_OP = 'UPDATE' THEN -- re-ingest?
-        PERFORM * FROM config.internal_flag WHERE name = 'ingest.reingest.force_on_same_marc' AND enabled;
-
-        IF NOT FOUND AND OLD.marc = NEW.marc THEN -- don't do anything if the MARC didn't change
-            RETURN NEW;
-        END IF;
-    END IF;
-
-    -- Record authority linking
-    PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_authority_linking' AND enabled;
-    IF NOT FOUND THEN
-        PERFORM biblio.map_authority_linking( NEW.id, NEW.marc );
-    END IF;
-
-    -- Flatten and insert the mfr data
-    PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_metabib_full_rec' AND enabled;
-    IF NOT FOUND THEN
-        PERFORM metabib.reingest_metabib_full_rec(NEW.id);
-
-        -- Now we pull out attribute data, which is dependent on the mfr for all but XPath-based fields
-        PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_metabib_rec_descriptor' AND enabled;
-        IF NOT FOUND THEN
-            PERFORM metabib.reingest_record_attributes(NEW.id, NULL, NEW.marc, TG_OP = 'INSERT' OR OLD.deleted);
-        END IF;
-    END IF;
-
-    -- Gather and insert the field entry data
-    PERFORM metabib.reingest_metabib_field_entries(NEW.id);
-
-    -- Located URI magic
-    IF TG_OP = 'INSERT' THEN
-        PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_located_uri' AND enabled;
-        IF NOT FOUND THEN
-            PERFORM biblio.extract_located_uris( NEW.id, NEW.marc, NEW.editor );
-        END IF;
-    ELSE
-        PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_located_uri' AND enabled;
-        IF NOT FOUND THEN
-            PERFORM biblio.extract_located_uris( NEW.id, NEW.marc, NEW.editor );
-        END IF;
-    END IF;
-
-    -- (re)map metarecord-bib linking
-    IF TG_OP = 'INSERT' THEN -- if not deleted and performing an insert, check for the flag
-        PERFORM * FROM config.internal_flag WHERE name = 'ingest.metarecord_mapping.skip_on_insert' AND enabled;
-        IF NOT FOUND THEN
-            PERFORM metabib.remap_metarecord_for_bib( NEW.id, NEW.fingerprint );
-        END IF;
-    ELSE -- we're doing an update, and we're not deleted, remap
-        PERFORM * FROM config.internal_flag WHERE name = 'ingest.metarecord_mapping.skip_on_update' AND enabled;
-        IF NOT FOUND THEN
-            PERFORM metabib.remap_metarecord_for_bib( NEW.id, NEW.fingerprint );
-        END IF;
-    END IF;
-
-    RETURN NEW;
-END;
-$func$ LANGUAGE PLPGSQL;
-
-CREATE OR REPLACE FUNCTION unapi.mmr (
-    obj_id BIGINT,
-    format TEXT,
-    ename TEXT,
-    includes TEXT[],
-    org TEXT,
-    depth INT DEFAULT NULL,
-    slimit HSTORE DEFAULT NULL,
-    soffset HSTORE DEFAULT NULL,
-    include_xmlns BOOL DEFAULT TRUE,
-    pref_lib INT DEFAULT NULL
-)
-RETURNS XML AS $F$
-DECLARE
-    mmrec   metabib.metarecord%ROWTYPE;
-    leadrec biblio.record_entry%ROWTYPE;
-    subrec biblio.record_entry%ROWTYPE;
-    layout  unapi.bre_output_layout%ROWTYPE;
-    xfrm    config.xml_transform%ROWTYPE;
-    ouid    INT;
-    xml_buf TEXT; -- growing XML document
-    tmp_xml TEXT; -- single-use XML string
-    xml_frag TEXT; -- single-use XML fragment
-    top_el  TEXT;
-    output  XML;
-    hxml    XML;
-    axml    XML;
-    subxml  XML; -- subordinate records elements
-    sub_xpath TEXT; 
-    parts   TEXT[]; 
-BEGIN
-
-    -- xpath for extracting bre.marc values from subordinate records 
-    -- so they may be appended to the MARC of the master record prior
-    -- to XSLT processing.
-    -- subjects, isbn, issn, upc -- anything else?
-    sub_xpath := 
-      '//*[starts-with(@tag, "6") or @tag="020" or @tag="022" or @tag="024"]';
-
-    IF org = '-' OR org IS NULL THEN
-        SELECT shortname INTO org FROM evergreen.org_top();
-    END IF;
-
-    SELECT id INTO ouid FROM actor.org_unit WHERE shortname = org;
-
-    IF ouid IS NULL THEN
-        RETURN NULL::XML;
-    END IF;
-
-    SELECT INTO mmrec * FROM metabib.metarecord WHERE id = obj_id;
-    IF NOT FOUND THEN
-        RETURN NULL::XML;
-    END IF;
-
-    -- TODO: aggregate holdings from constituent records
-    IF format = 'holdings_xml' THEN -- the special case
-        output := unapi.mmr_holdings_xml(
-            obj_id, ouid, org, depth,
-            evergreen.array_remove_item_by_value(includes,'holdings_xml'),
-            slimit, soffset, include_xmlns, pref_lib);
-        RETURN output;
-    END IF;
-
-    SELECT * INTO layout FROM unapi.bre_output_layout WHERE name = format;
-
-    IF layout.name IS NULL THEN
-        RETURN NULL::XML;
-    END IF;
-
-    SELECT * INTO xfrm FROM config.xml_transform WHERE name = layout.transform;
-
-    SELECT INTO leadrec * FROM biblio.record_entry WHERE id = mmrec.master_record;
-
-    -- Grab distinct MVF for all records if requested
-    IF ('mra' = ANY (includes)) THEN 
-        axml := unapi.mmr_mra(obj_id,NULL,NULL,NULL,org,depth,NULL,NULL,TRUE,pref_lib);
-    ELSE
-        axml := NULL::XML;
-    END IF;
-
-    xml_buf = leadrec.marc;
-
-    hxml := NULL::XML;
-    IF ('holdings_xml' = ANY (includes)) THEN
-        hxml := unapi.mmr_holdings_xml(
-                    obj_id, ouid, org, depth,
-                    evergreen.array_remove_item_by_value(includes,'holdings_xml'),
-                    slimit, soffset, include_xmlns, pref_lib);
-    END IF;
-
-    subxml := NULL::XML;
-    parts := '{}'::TEXT[];
-    FOR subrec IN SELECT bre.* FROM biblio.record_entry bre
-         JOIN metabib.metarecord_source_map mmsm ON (mmsm.source = bre.id)
-         JOIN metabib.metarecord mmr ON (mmr.id = mmsm.metarecord)
-         WHERE mmr.id = obj_id AND NOT bre.deleted
-         ORDER BY CASE WHEN bre.id = mmr.master_record THEN 0 ELSE bre.id END
-         LIMIT COALESCE((slimit->'bre')::INT, 5) LOOP
-
-        IF subrec.id = leadrec.id THEN CONTINUE; END IF;
-        -- Append choice data from the the non-lead records to the 
-        -- the lead record document
-
-        parts := parts || xpath(sub_xpath, subrec.marc::XML)::TEXT[];
-    END LOOP;
-
-    SELECT ARRAY_TO_STRING( ARRAY_AGG( DISTINCT p ), '' )::XML INTO subxml FROM UNNEST(parts) p;
-
-    -- append data from the subordinate records to the 
-    -- main record document before applying the XSLT
-
-    IF subxml IS NOT NULL THEN 
-        xml_buf := REGEXP_REPLACE(xml_buf, 
-            '</record>(.*?)$', subxml || '</record>' || E'\\1');
-    END IF;
-
-    IF format = 'marcxml' THEN
-         -- If we're not using the prefixed namespace in 
-         -- this record, then remove all declarations of it
-        IF xml_buf !~ E'<marc:' THEN
-           xml_buf := REGEXP_REPLACE(xml_buf, 
-            ' xmlns:marc="http://www.loc.gov/MARC21/slim"', '', 'g');
-        END IF; 
-    ELSE
-        xml_buf := oils_xslt_process(xml_buf, xfrm.xslt)::XML;
-    END IF;
-
-    -- update top_el to reflect the change in xml_buf, which may
-    -- now be a different type of document (e.g. record -> mods)
-    top_el := REGEXP_REPLACE(xml_buf, E'^.*?<((?:\\S+:)?' || 
-        layout.holdings_element || ').*$', E'\\1');
-
-    IF axml IS NOT NULL THEN 
-        xml_buf := REGEXP_REPLACE(xml_buf, 
-            '</' || top_el || '>(.*?)$', axml || '</' || top_el || E'>\\1');
-    END IF;
-
-    IF hxml IS NOT NULL THEN
-        xml_buf := REGEXP_REPLACE(xml_buf, 
-            '</' || top_el || '>(.*?)$', hxml || '</' || top_el || E'>\\1');
-    END IF;
-
-    IF ('mmr.unapi' = ANY (includes)) THEN 
-        output := REGEXP_REPLACE(
-            xml_buf,
-            '</' || top_el || '>(.*?)',
-            XMLELEMENT(
-                name abbr,
-                XMLATTRIBUTES(
-                    'http://www.w3.org/1999/xhtml' AS xmlns,
-                    'unapi-id' AS class,
-                    'tag:open-ils.org:U2@mmr/' || obj_id || '/' || org AS title
-                )
-            )::TEXT || '</' || top_el || E'>\\1'
-        );
-    ELSE
-        output := xml_buf;
-    END IF;
-
-    -- remove ignorable whitesace
-    output := REGEXP_REPLACE(output::TEXT,E'>\\s+<','><','gs')::XML;
-    RETURN output;
-END;
-$F$ LANGUAGE PLPGSQL STABLE;
-
--- Forcibly remap deleted master records, retaining the linkage if so configured.
-SELECT  metabib.remap_metarecord_for_bib( bre.id, bre.fingerprint, TRUE, COALESCE(flag.enabled,FALSE))
-  FROM  metabib.metarecord metar
-        JOIN biblio.record_entry bre ON bre.id = metar.master_record,
-        config.internal_flag flag
-  WHERE bre.deleted = TRUE AND flag.name = 'ingest.metarecord_mapping.preserve_on_delete';
-
-COMMIT;
-