]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/sql/Pg/upgrade/0145.schema.more-8.3-8.4-transitional-xml-fixes.sql
Break up expensive queries, match index to quals
[working/Evergreen.git] / Open-ILS / src / sql / Pg / upgrade / 0145.schema.more-8.3-8.4-transitional-xml-fixes.sql
1
2 BEGIN;
3
4 INSERT INTO config.upgrade_log (version) VALUES ('0145'); -- miker
5
6 CREATE FUNCTION version_specific_xpath () RETURNS TEXT AS $wrapper_function$
7 DECLARE
8     out_text TEXT;
9 BEGIN
10     
11     IF REGEXP_REPLACE(VERSION(),E'^.+?(\\d+\\.\\d+).*?$',E'\\1')::FLOAT < 8.3 THEN
12         out_text := 'Creating XPath functions that work like the native XPATH function in 8.3+';
13         
14         EXECUTE $create_82_funcs$
15                         
16 CREATE OR REPLACE FUNCTION oils_xpath ( xpath TEXT, xml TEXT, ns ANYARRAY ) RETURNS TEXT[] AS $func$
17 DECLARE
18     node_text   TEXT;
19     ns_regexp   TEXT;
20     munged_xpath    TEXT;
21 BEGIN
22
23     munged_xpath := xpath;
24
25     IF ns IS NOT NULL AND array_upper(ns, 1) IS NOT NULL THEN
26         FOR namespace IN 1 .. array_upper(ns, 1) LOOP
27             munged_xpath := REGEXP_REPLACE(
28                 munged_xpath,
29                 E'(' || ns[namespace][1] || E'):(\\w+)',
30                 E'*[local-name() = "\\2" and namespace-uri() = "' || ns[namespace][2] || E'"]',
31                 'g'
32             );
33         END LOOP;
34
35         munged_xpath := REGEXP_REPLACE( munged_xpath, E'\\]\\[(\\D)',E' and \\1', 'g');
36     END IF;
37
38     -- RAISE NOTICE 'munged xpath: %', munged_xpath;
39
40     node_text := xpath_nodeset(xml, munged_xpath, 'XXX_OILS_NODESET');
41     -- RAISE NOTICE 'node_text: %', node_text;
42
43     IF munged_xpath ~ $re$/[^/[]*@[^/]+$$re$ THEN
44         node_text := REGEXP_REPLACE(node_text,'<XXX_OILS_NODESET>[^"]+"', '<XXX_OILS_NODESET>', 'g');
45         node_text := REGEXP_REPLACE(node_text,'"</XXX_OILS_NODESET>', '</XXX_OILS_NODESET>', 'g');
46     END IF;
47
48     node_text := REGEXP_REPLACE(node_text,'^<XXX_OILS_NODESET>', '');
49     node_text := REGEXP_REPLACE(node_text,'</XXX_OILS_NODESET>$', '');
50
51     RETURN  STRING_TO_ARRAY(node_text, '</XXX_OILS_NODESET><XXX_OILS_NODESET>');
52 END;
53 $func$ LANGUAGE PLPGSQL;
54
55 CREATE OR REPLACE FUNCTION oils_xpath ( TEXT, TEXT ) RETURNS TEXT[] AS $$SELECT oils_xpath( $1, $2, '{}'::TEXT[] );$$ LANGUAGE SQL;
56
57 CREATE OR REPLACE FUNCTION oils_xslt_process(TEXT, TEXT) RETURNS TEXT AS $$
58     SELECT xslt_process( $1, $2 );
59 $$ LANGUAGE SQL;
60
61         $create_82_funcs$;
62     ELSIF REGEXP_REPLACE(VERSION(),E'^.+?(\\d+\\.\\d+).*?$',E'\\1')::FLOAT = 8.3 THEN
63         out_text := 'Creating XPath wrapper functions around the native XPATH function in 8.3.  contrib/xml2 still required!';
64
65         EXECUTE $create_83_funcs$
66 -- 8.3 or after
67 CREATE OR REPLACE FUNCTION oils_xpath ( TEXT, TEXT, ANYARRAY ) RETURNS TEXT[] AS 'SELECT XPATH( $1, $2::XML, $3 )::TEXT[];' LANGUAGE SQL;
68 CREATE OR REPLACE FUNCTION oils_xpath ( TEXT, TEXT ) RETURNS TEXT[] AS 'SELECT XPATH( $1, $2::XML )::TEXT[];' LANGUAGE SQL;
69
70 CREATE OR REPLACE FUNCTION oils_xslt_process(TEXT, TEXT) RETURNS TEXT AS $$
71     SELECT xslt_process( $1, $2 );
72 $$ LANGUAGE SQL;
73
74         $create_83_funcs$;
75
76     ELSE
77         out_text := 'Creating XPath wrapper functions around the native XPATH function in 8.4+, and plperlu-based xslt processor.  No contrib/xml2 needed!';
78
79         EXECUTE $create_84_funcs$
80 -- 8.4 or after
81 CREATE OR REPLACE FUNCTION oils_xpath ( TEXT, TEXT, ANYARRAY ) RETURNS TEXT[] AS 'SELECT XPATH( $1, $2::XML, $3 )::TEXT[];' LANGUAGE SQL;
82 CREATE OR REPLACE FUNCTION oils_xpath ( TEXT, TEXT ) RETURNS TEXT[] AS 'SELECT XPATH( $1, $2::XML )::TEXT[];' LANGUAGE SQL;
83
84 CREATE OR REPLACE FUNCTION oils_xslt_process(TEXT, TEXT) RETURNS TEXT AS $func$
85   use strict;
86
87   use XML::LibXSLT;
88   use XML::LibXML;
89
90   my $doc = shift;
91   my $xslt = shift;
92
93   # The following approach uses the older XML::LibXML 1.69 / XML::LibXSLT 1.68
94   # methods of parsing XML documents and stylesheets, in the hopes of broader
95   # compatibility with distributions
96   my $parser = $_SHARED{'_xslt_process'}{parsers}{xml} || XML::LibXML->new();
97
98   # Cache the XML parser, if we do not already have one
99   $_SHARED{'_xslt_process'}{parsers}{xml} = $parser
100     unless ($_SHARED{'_xslt_process'}{parsers}{xml});
101
102   my $xslt_parser = $_SHARED{'_xslt_process'}{parsers}{xslt} || XML::LibXSLT->new();
103
104   # Cache the XSLT processor, if we do not already have one
105   $_SHARED{'_xslt_process'}{parsers}{xslt} = $xslt_parser
106     unless ($_SHARED{'_xslt_process'}{parsers}{xslt});
107
108   my $stylesheet = $_SHARED{'_xslt_process'}{stylesheets}{$xslt} ||
109     $xslt_parser->parse_stylesheet( $parser->parse_string($xslt) );
110
111   $_SHARED{'_xslt_process'}{stylesheets}{$xslt} = $stylesheet
112     unless ($_SHARED{'_xslt_process'}{stylesheets}{$xslt});
113
114   return $stylesheet->output_string(
115     $stylesheet->transform(
116       $parser->parse_string($doc)
117     )
118   );
119
120 $func$ LANGUAGE 'plperlu' STRICT IMMUTABLE;
121
122         $create_84_funcs$;
123
124     END IF;
125
126     RETURN out_text;
127 END;
128 $wrapper_function$ LANGUAGE PLPGSQL;
129
130 SELECT version_specific_xpath();
131 DROP FUNCTION version_specific_xpath();
132
133
134 CREATE OR REPLACE FUNCTION oils_xpath_string ( TEXT, TEXT, TEXT, ANYARRAY ) RETURNS TEXT AS $func$
135     SELECT  ARRAY_TO_STRING(
136                 oils_xpath(
137                     $1 ||
138                         CASE WHEN $1 ~ $re$/[^/[]*@[^/]+$$re$ OR $1 ~ $re$text\(\)$$re$ THEN '' ELSE '//text()' END,
139                     $2,
140                     $4
141                 ),
142                 $3
143             );
144 $func$ LANGUAGE SQL;
145
146 CREATE OR REPLACE FUNCTION oils_xpath_string ( TEXT, TEXT, TEXT ) RETURNS TEXT AS $func$
147     SELECT oils_xpath_string( $1, $2, $3, '{}'::TEXT[] );
148 $func$ LANGUAGE SQL;
149
150 CREATE OR REPLACE FUNCTION oils_xpath_string ( TEXT, TEXT ) RETURNS TEXT AS $func$
151     SELECT oils_xpath_string( $1, $2, '{}'::TEXT[] );
152 $func$ LANGUAGE SQL;
153
154
155
156 CREATE OR REPLACE FUNCTION extract_marc_field ( TEXT, BIGINT, TEXT, TEXT ) RETURNS TEXT AS $$
157 DECLARE
158     query TEXT;
159     output TEXT;
160 BEGIN
161     query := $q$
162         SELECT  regexp_replace(
163                     oils_xpath_string(
164                         $q$ || quote_literal($3) || $q$,
165                         marc,
166                         ' '
167                     ),
168                     $q$ || quote_literal($4) || $q$,
169                     '',
170                     'g')
171           FROM  $q$ || $1 || $q$
172           WHERE id = $q$ || $2;
173
174     EXECUTE query INTO output;
175
176     -- RAISE NOTICE 'query: %, output; %', query, output;
177
178     RETURN output;
179 END;
180 $$ LANGUAGE PLPGSQL;
181
182 COMMIT;
183