--- /dev/null
--- /dev/null
++-- Evergreen DB patch 0549.unnest_oils_xpath_table.sql
++--
++-- Replace usage of custom explode_array() function with native unnest()
++--
++BEGIN;
++
++-- check whether patch can be applied
++SELECT evergreen.upgrade_deps_block_check('0549', :eg_version);
++
++CREATE OR REPLACE FUNCTION oils_xpath_table ( key TEXT, document_field TEXT, relation_name TEXT, xpaths TEXT, criteria TEXT ) RETURNS SETOF RECORD AS $func$
++DECLARE
++ xpath_list TEXT[];
++ select_list TEXT[];
++ where_list TEXT[];
++ q TEXT;
++ out_record RECORD;
++ empty_test RECORD;
++BEGIN
++ xpath_list := STRING_TO_ARRAY( xpaths, '|' );
++
++ select_list := ARRAY_APPEND( select_list, key || '::INT AS key' );
++
++ FOR i IN 1 .. ARRAY_UPPER(xpath_list,1) LOOP
++ IF xpath_list[i] = 'null()' THEN
++ select_list := ARRAY_APPEND( select_list, 'NULL::TEXT AS c_' || i );
++ ELSE
++ select_list := ARRAY_APPEND(
++ select_list,
++ $sel$
++ unnest(
++ COALESCE(
++ NULLIF(
++ oils_xpath(
++ $sel$ ||
++ quote_literal(
++ CASE
++ WHEN xpath_list[i] ~ $re$/[^/[]*@[^/]+$$re$ OR xpath_list[i] ~ $re$text\(\)$$re$ THEN xpath_list[i]
++ ELSE xpath_list[i] || '//text()'
++ END
++ ) ||
++ $sel$,
++ $sel$ || document_field || $sel$
++ ),
++ '{}'::TEXT[]
++ ),
++ '{NULL}'::TEXT[]
++ )
++ ) AS c_$sel$ || i
++ );
++ where_list := ARRAY_APPEND(
++ where_list,
++ 'c_' || i || ' IS NOT NULL'
++ );
++ END IF;
++ END LOOP;
++
++ q := $q$
++SELECT * FROM (
++ SELECT $q$ || ARRAY_TO_STRING( select_list, ', ' ) || $q$ FROM $q$ || relation_name || $q$ WHERE ($q$ || criteria || $q$)
++)x WHERE $q$ || ARRAY_TO_STRING( where_list, ' OR ' );
++ -- RAISE NOTICE 'query: %', q;
++
++ FOR out_record IN EXECUTE q LOOP
++ RETURN NEXT out_record;
++ END LOOP;
++
++ RETURN;
++END;
++$func$ LANGUAGE PLPGSQL IMMUTABLE;
++
++COMMIT;
--- /dev/null
--- /dev/null
++-- Evergreen DB patch 0550.unnest_biblio_extract_metabib_field_entry.sql
++--
++-- Replace usage of custom explode_array() function with native unnest()
++--
++BEGIN;
++
++-- check whether patch can be applied
++SELECT evergreen.upgrade_deps_block_check('0550', :eg_version);
++
++CREATE OR REPLACE FUNCTION biblio.extract_metabib_field_entry ( rid BIGINT, default_joiner TEXT ) RETURNS SETOF metabib.field_entry_template AS $func$
++DECLARE
++ bib biblio.record_entry%ROWTYPE;
++ idx config.metabib_field%ROWTYPE;
++ xfrm config.xml_transform%ROWTYPE;
++ prev_xfrm TEXT;
++ transformed_xml TEXT;
++ xml_node TEXT;
++ xml_node_list TEXT[];
++ facet_text TEXT;
++ raw_text TEXT;
++ curr_text TEXT;
++ joiner TEXT := default_joiner; -- XXX will index defs supply a joiner?
++ output_row metabib.field_entry_template%ROWTYPE;
++BEGIN
++
++ -- Get the record
++ SELECT INTO bib * FROM biblio.record_entry WHERE id = rid;
++
++ -- Loop over the indexing entries
++ FOR idx IN SELECT * FROM config.metabib_field ORDER BY format LOOP
++
++ SELECT INTO xfrm * from config.xml_transform WHERE name = idx.format;
++
++ -- See if we can skip the XSLT ... it's expensive
++ IF prev_xfrm IS NULL OR prev_xfrm <> xfrm.name THEN
++ -- Can't skip the transform
++ IF xfrm.xslt <> '---' THEN
++ transformed_xml := oils_xslt_process(bib.marc,xfrm.xslt);
++ ELSE
++ transformed_xml := bib.marc;
++ END IF;
++
++ prev_xfrm := xfrm.name;
++ END IF;
++
++ xml_node_list := oils_xpath( idx.xpath, transformed_xml, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
++
++ raw_text := NULL;
++ FOR xml_node IN SELECT x FROM unnest(xml_node_list) AS x LOOP
++ CONTINUE WHEN xml_node !~ E'^\\s*<';
++
++ curr_text := ARRAY_TO_STRING(
++ oils_xpath( '//text()',
++ REGEXP_REPLACE( -- This escapes all &s not followed by "amp;". Data ise returned from oils_xpath (above) in UTF-8, not entity encoded
++ REGEXP_REPLACE( -- This escapes embeded <s
++ xml_node,
++ $re$(>[^<]+)(<)([^>]+<)$re$,
++ E'\\1<\\3',
++ 'g'
++ ),
++ '&(?!amp;)',
++ '&',
++ 'g'
++ )
++ ),
++ ' '
++ );
++
++ CONTINUE WHEN curr_text IS NULL OR curr_text = '';
++
++ IF raw_text IS NOT NULL THEN
++ raw_text := raw_text || joiner;
++ END IF;
++
++ raw_text := COALESCE(raw_text,'') || curr_text;
++
++ -- insert raw node text for faceting
++ IF idx.facet_field THEN
++
++ IF idx.facet_xpath IS NOT NULL AND idx.facet_xpath <> '' THEN
++ facet_text := oils_xpath_string( idx.facet_xpath, xml_node, joiner, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
++ ELSE
++ facet_text := curr_text;
++ END IF;
++
++ output_row.field_class = idx.field_class;
++ output_row.field = -1 * idx.id;
++ output_row.source = rid;
++ output_row.value = BTRIM(REGEXP_REPLACE(facet_text, E'\\s+', ' ', 'g'));
++
++ RETURN NEXT output_row;
++ END IF;
++
++ END LOOP;
++
++ CONTINUE WHEN raw_text IS NULL OR raw_text = '';
++
++ -- insert combined node text for searching
++ IF idx.search_field THEN
++ output_row.field_class = idx.field_class;
++ output_row.field = idx.id;
++ output_row.source = rid;
++ output_row.value = BTRIM(REGEXP_REPLACE(raw_text, E'\\s+', ' ', 'g'));
++
++ RETURN NEXT output_row;
++ END IF;
++
++ END LOOP;
++
++END;
++$func$ LANGUAGE PLPGSQL;
++
++COMMIT;