]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/sql/Pg/020.schema.functions.sql
protect standard numbers from NACO normalization; make sure normalized text is proper...
[working/Evergreen.git] / Open-ILS / src / sql / Pg / 020.schema.functions.sql
1 /*
2  * Copyright (C) 2004-2008  Georgia Public Library Service
3  * Copyright (C) 2007-2008  Equinox Software, Inc.
4  * Mike Rylander <miker@esilibrary.com> 
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  */
17
18 CREATE OR REPLACE FUNCTION public.non_filing_normalize ( TEXT, "char" ) RETURNS TEXT AS $$
19         SELECT  SUBSTRING(
20                         REGEXP_REPLACE(
21                                 REGEXP_REPLACE(
22                                         $1,
23                                         E'\W*$',
24                                         ''
25                                 ),
26                                 '  ',
27                                 ' '
28                         ),
29                         CASE
30                                 WHEN $2::INT NOT BETWEEN 48 AND 57 THEN 1
31                                 ELSE $2::TEXT::INT + 1
32                         END
33                 );
34 $$ LANGUAGE SQL STRICT IMMUTABLE;
35
36 CREATE OR REPLACE FUNCTION public.naco_normalize( TEXT, TEXT ) RETURNS TEXT AS $func$
37     use Unicode::Normalize;
38     use Encode;
39
40         my $txt = lc(encode_utf8(shift));
41         my $sf = shift;
42
43     $txt = NFD($txt);
44         $txt =~ s/\pM+//go;     # Remove diacritics
45
46         $txt =~ s/\xE6/AE/go;   # Convert ae digraph
47         $txt =~ s/\x{153}/OE/go;# Convert oe digraph
48         $txt =~ s/\xFE/TH/go;   # Convert Icelandic thorn
49
50         $txt =~ tr/\x{2070}\x{2071}\x{2072}\x{2073}\x{2074}\x{2075}\x{2076}\x{2077}\x{2078}\x{2079}\x{207A}\x{207B}/0123456789+-/;# Convert superscript numbers
51         $txt =~ tr/\x{2080}\x{2081}\x{2082}\x{2083}\x{2084}\x{2085}\x{2086}\x{2087}\x{2088}\x{2089}\x{208A}\x{208B}/0123456889+-/;# Convert subscript numbers
52
53         $txt =~ tr/\x{0251}\x{03B1}\x{03B2}\x{0262}\x{03B3}/AABGG/;             # Convert Latin and Greek
54         $txt =~ tr/\x{2113}\xF0\!\"\(\)\-\{\}\<\>\;\:\.\?\xA1\xBF\/\\\@\*\%\=\xB1\+\xAE\xA9\x{2117}\$\xA3\x{FFE1}\xB0\^\_\~\`/LD /;     # Convert Misc
55         $txt =~ tr/\'\[\]\|//d;                                                 # Remove Misc
56
57         if ($sf && $sf =~ /^a/o) {
58                 my $commapos = index($txt,',');
59                 if ($commapos > -1) {
60                         if ($commapos != length($txt) - 1) {
61                                 my @list = split /,/, $txt;
62                                 my $first = shift @list;
63                                 $txt = $first . ',' . join(' ', @list);
64                         } else {
65                                 $txt =~ s/,/ /go;
66                         }
67                 }
68         } else {
69                 $txt =~ s/,/ /go;
70         }
71
72         $txt =~ s/\s+/ /go;     # Compress multiple spaces
73         $txt =~ s/^\s+//o;      # Remove leading space
74         $txt =~ s/\s+$//o;      # Remove trailing space
75
76         return $txt;
77 $func$ LANGUAGE 'plperlu' STRICT IMMUTABLE;
78
79 CREATE OR REPLACE FUNCTION public.naco_normalize( TEXT ) RETURNS TEXT AS $func$
80         SELECT public.naco_normalize($1,'');
81 $func$ LANGUAGE 'sql' STRICT IMMUTABLE;
82
83 CREATE OR REPLACE FUNCTION public.first_word ( TEXT ) RETURNS TEXT AS $$
84         SELECT SUBSTRING( $1 FROM $_$^\S+$_$);
85 $$ LANGUAGE SQL;
86
87 CREATE OR REPLACE FUNCTION public.naco_normalize_keep_comma( TEXT ) RETURNS TEXT AS $func$
88         SELECT public.naco_normalize($1,'a');
89 $func$ LANGUAGE SQL STRICT IMMUTABLE;
90
91 CREATE OR REPLACE FUNCTION public.normalize_space( TEXT ) RETURNS TEXT AS $$
92     SELECT regexp_replace(regexp_replace(regexp_replace($1, E'\\n', ' ', 'g'), E'(?:^\\s+)|(\\s+$)', '', 'g'), E'\\s+', ' ', 'g');
93 $$ LANGUAGE SQL;
94
95 CREATE OR REPLACE FUNCTION public.lowercase( TEXT ) RETURNS TEXT AS $$
96     return lc(shift);
97 $$ LANGUAGE PLPERLU;
98
99 CREATE OR REPLACE FUNCTION public.uppercase( TEXT ) RETURNS TEXT AS $$
100     return uc(shift);
101 $$ LANGUAGE PLPERLU;
102
103 CREATE OR REPLACE FUNCTION public.remove_diacritics( TEXT ) RETURNS TEXT AS $$
104     use Unicode::Normalize;
105
106     my $x = NFD(shift);
107     $x =~ s/\pM+//go;
108     return $x;
109
110 $$ LANGUAGE PLPERLU;
111
112 CREATE OR REPLACE FUNCTION public.entityize( TEXT ) RETURNS TEXT AS $$
113     use Unicode::Normalize;
114
115     my $x = NFC(shift);
116     $x =~ s/([\x{0080}-\x{fffd}])/sprintf('&#x%X;',ord($1))/sgoe;
117     return $x;
118
119 $$ LANGUAGE PLPERLU;
120
121 CREATE OR REPLACE FUNCTION public.call_number_dewey( TEXT ) RETURNS TEXT AS $$
122         my $txt = shift;
123         $txt =~ s/^\s+//o;
124         $txt =~ s/[\[\]\{\}\(\)`'"#<>\*\?\-\+\$\\]+//og;
125         $txt =~ s/\s+$//o;
126         if ($txt =~ /(\d{3}(?:\.\d+)?)/o) {
127                 return $1;
128         } else {
129                 return (split /\s+/, $txt)[0];
130         }
131 $$ LANGUAGE 'plperlu' STRICT IMMUTABLE;
132
133 CREATE OR REPLACE FUNCTION public.call_number_dewey( TEXT, INT ) RETURNS TEXT AS $$
134         SELECT SUBSTRING(call_number_dewey($1) FROM 1 FOR $2);
135 $$ LANGUAGE SQL STRICT IMMUTABLE;
136
137 CREATE OR REPLACE FUNCTION tableoid2name ( oid ) RETURNS TEXT AS $$
138         BEGIN
139                 RETURN $1::regclass;
140         END;
141 $$ language 'plpgsql';
142
143
144 CREATE OR REPLACE FUNCTION actor.org_unit_descendants ( INT ) RETURNS SETOF actor.org_unit AS $$
145         SELECT  a.*
146           FROM  connectby('actor.org_unit'::text,'id'::text,'parent_ou'::text,'name'::text,$1::text,100,'.'::text)
147                         AS t(keyid text, parent_keyid text, level int, branch text,pos int)
148                 JOIN actor.org_unit a ON a.id::text = t.keyid::text
149           ORDER BY  CASE WHEN a.parent_ou IS NULL THEN 0 ELSE 1 END, a.name;
150 $$ LANGUAGE SQL STABLE;
151
152 CREATE OR REPLACE FUNCTION actor.org_unit_ancestors ( INT ) RETURNS SETOF actor.org_unit AS $$
153         SELECT  a.*
154           FROM  connectby('actor.org_unit'::text,'parent_ou'::text,'id'::text,'name'::text,$1::text,100,'.'::text)
155                         AS t(keyid text, parent_keyid text, level int, branch text,pos int)
156                 JOIN actor.org_unit a ON a.id::text = t.keyid::text
157         JOIN actor.org_unit_type tp ON tp.id = a.ou_type 
158         ORDER BY tp.depth, a.name;
159 $$ LANGUAGE SQL STABLE;
160
161 CREATE OR REPLACE FUNCTION actor.org_unit_descendants ( INT,INT ) RETURNS SETOF actor.org_unit AS $$
162         SELECT  a.*
163           FROM  connectby('actor.org_unit'::text,'id'::text,'parent_ou'::text,'name'::text,
164                                 (SELECT x.id
165                                    FROM actor.org_unit_ancestors($1) x
166                                         JOIN actor.org_unit_type y ON x.ou_type = y.id
167                                   WHERE y.depth = $2)::text
168                 ,100,'.'::text)
169                         AS t(keyid text, parent_keyid text, level int, branch text,pos int)
170                 JOIN actor.org_unit a ON a.id::text = t.keyid::text
171           ORDER BY  CASE WHEN a.parent_ou IS NULL THEN 0 ELSE 1 END, a.name;
172 $$ LANGUAGE SQL STABLE;
173
174 CREATE OR REPLACE FUNCTION actor.org_unit_ancestor_at_depth ( INT,INT ) RETURNS actor.org_unit AS $$
175         SELECT  a.*
176           FROM  actor.org_unit a
177           WHERE id = ( SELECT FIRST(x.id)
178                          FROM   actor.org_unit_ancestors($1) x
179                                 JOIN actor.org_unit_type y
180                                         ON x.ou_type = y.id AND y.depth = $2);
181 $$ LANGUAGE SQL STABLE;
182
183 CREATE OR REPLACE FUNCTION actor.org_unit_full_path ( INT ) RETURNS SETOF actor.org_unit AS $$
184         SELECT  *
185           FROM  actor.org_unit_ancestors($1)
186                         UNION
187         SELECT  *
188           FROM  actor.org_unit_descendants($1);
189 $$ LANGUAGE SQL STABLE;
190
191 CREATE OR REPLACE FUNCTION actor.org_unit_full_path ( INT, INT ) RETURNS SETOF actor.org_unit AS $$
192         SELECT  * FROM actor.org_unit_full_path((actor.org_unit_ancestor_at_depth($1, $2)).id)
193 $$ LANGUAGE SQL STABLE;
194
195 CREATE OR REPLACE FUNCTION actor.org_unit_combined_ancestors ( INT, INT ) RETURNS SETOF actor.org_unit AS $$
196         SELECT  *
197           FROM  actor.org_unit_ancestors($1)
198                         UNION
199         SELECT  *
200           FROM  actor.org_unit_ancestors($2);
201 $$ LANGUAGE SQL STABLE;
202
203 CREATE OR REPLACE FUNCTION actor.org_unit_common_ancestors ( INT, INT ) RETURNS SETOF actor.org_unit AS $$
204         SELECT  *
205           FROM  actor.org_unit_ancestors($1)
206                         INTERSECT
207         SELECT  *
208           FROM  actor.org_unit_ancestors($2);
209 $$ LANGUAGE SQL STABLE;
210
211 CREATE OR REPLACE FUNCTION actor.org_unit_proximity ( INT, INT ) RETURNS INT AS $$
212         SELECT COUNT(id)::INT FROM (
213                 SELECT id FROM actor.org_unit_combined_ancestors($1, $2)
214                         EXCEPT
215                 SELECT id FROM actor.org_unit_common_ancestors($1, $2)
216         ) z;
217 $$ LANGUAGE SQL STABLE;
218
219 CREATE OR REPLACE FUNCTION actor.org_unit_ancestor_setting( setting_name TEXT, org_id INT ) RETURNS SETOF actor.org_unit_setting AS $$
220 DECLARE
221     setting RECORD;
222     cur_org INT;
223 BEGIN
224     cur_org := org_id;
225     LOOP
226         SELECT INTO setting * FROM actor.org_unit_setting WHERE org_unit = cur_org AND name = setting_name;
227         IF FOUND THEN
228             RETURN NEXT setting;
229         END IF;
230         SELECT INTO cur_org parent_ou FROM actor.org_unit WHERE id = cur_org;
231         EXIT WHEN cur_org IS NULL;
232     END LOOP;
233     RETURN;
234 END;
235 $$ LANGUAGE plpgsql;
236
237 COMMENT ON FUNCTION actor.org_unit_ancestor_setting( TEXT, INT) IS $$
238 /**
239 * Search "up" the org_unit tree until we find the first occurrence of an 
240 * org_unit_setting with the given name.
241 */
242 $$;
243