34a2ee0a44b341a2db3dfcfa828d351cb2ec4c15
[transitory.git] / Open-ILS / src / sql / Pg / upgrade / XXXX.schema.vandelay.import-match-no-like-any.sql
1 BEGIN;
2
3 -- XXXX.schema.vandelay.import-match-no-like-any.sql
4
5 SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version);
6
7 CREATE OR REPLACE FUNCTION vandelay.match_set_test_marcxml(
8     match_set_id INTEGER, record_xml TEXT
9 ) RETURNS SETOF vandelay.match_set_test_result AS $$
10 DECLARE
11     tags_rstore HSTORE;
12     svf_rstore  HSTORE;
13     coal        TEXT;
14     joins       TEXT;
15     query_      TEXT;
16     wq          TEXT;
17     qvalue      INTEGER;
18     rec         RECORD;
19 BEGIN
20     tags_rstore := vandelay.flatten_marc_hstore(record_xml);
21     svf_rstore := vandelay.extract_rec_attrs(record_xml);
22
23     CREATE TEMPORARY TABLE _vandelay_tmp_qrows (q INTEGER);
24     CREATE TEMPORARY TABLE _vandelay_tmp_jrows (j TEXT);
25
26     -- generate the where clause and return that directly (into wq), and as
27     -- a side-effect, populate the _vandelay_tmp_[qj]rows tables.
28     wq := vandelay.get_expr_from_match_set(match_set_id, tags_rstore);
29
30     query_ := 'SELECT DISTINCT(bre.id) AS record, ';
31
32     -- qrows table is for the quality bits we add to the SELECT clause
33     SELECT ARRAY_TO_STRING(
34         ARRAY_ACCUM('COALESCE(n' || q::TEXT || '.quality, 0)'), ' + '
35     ) INTO coal FROM _vandelay_tmp_qrows;
36
37     -- our query string so far is the SELECT clause and the inital FROM.
38     -- no JOINs yet nor the WHERE clause
39     query_ := query_ || coal || ' AS quality ' || E'\n' ||
40         'FROM biblio.record_entry bre ';
41
42     -- jrows table is for the joins we must make (and the real text conditions)
43     SELECT ARRAY_TO_STRING(ARRAY_ACCUM(j), E'\n') INTO joins
44         FROM _vandelay_tmp_jrows;
45
46     -- add those joins and the where clause to our query.
47     query_ := query_ || joins || E'\n' || 'WHERE ' || wq || ' AND not bre.deleted';
48
49     -- this will return rows of record,quality
50     RAISE WARNING '%', query_;
51     FOR rec IN EXECUTE query_ USING tags_rstore, svf_rstore LOOP
52         RETURN NEXT rec;
53     END LOOP;
54
55     DROP TABLE _vandelay_tmp_qrows;
56     DROP TABLE _vandelay_tmp_jrows;
57     RETURN;
58 END;
59
60 $$ LANGUAGE PLPGSQL;
61
62 CREATE OR REPLACE FUNCTION vandelay.get_expr_from_match_set(
63     match_set_id INTEGER,
64     tags_rstore HSTORE
65 ) RETURNS TEXT AS $$
66 DECLARE
67     root    vandelay.match_set_point;
68 BEGIN
69     SELECT * INTO root FROM vandelay.match_set_point
70         WHERE parent IS NULL AND match_set = match_set_id;
71
72     RETURN vandelay.get_expr_from_match_set_point(root, tags_rstore);
73 END;
74 $$  LANGUAGE PLPGSQL;
75
76 CREATE OR REPLACE FUNCTION vandelay.get_expr_from_match_set_point(
77     node vandelay.match_set_point,
78     tags_rstore HSTORE
79 ) RETURNS TEXT AS $$
80 DECLARE
81     q           TEXT;
82     i           INTEGER;
83     this_op     TEXT;
84     children    INTEGER[];
85     child       vandelay.match_set_point;
86 BEGIN
87     SELECT ARRAY_ACCUM(id) INTO children FROM vandelay.match_set_point
88         WHERE parent = node.id;
89
90     IF ARRAY_LENGTH(children, 1) > 0 THEN
91         this_op := vandelay._get_expr_render_one(node);
92         q := '(';
93         i := 1;
94         WHILE children[i] IS NOT NULL LOOP
95             SELECT * INTO child FROM vandelay.match_set_point
96                 WHERE id = children[i];
97             IF i > 1 THEN
98                 q := q || ' ' || this_op || ' ';
99             END IF;
100             i := i + 1;
101             q := q || vandelay.get_expr_from_match_set_point(child, tags_rstore);
102         END LOOP;
103         q := q || ')';
104         RETURN q;
105     ELSIF node.bool_op IS NULL THEN
106         PERFORM vandelay._get_expr_push_qrow(node);
107         PERFORM vandelay._get_expr_push_jrow(node, tags_rstore);
108         RETURN vandelay._get_expr_render_one(node);
109     ELSE
110         RETURN '';
111     END IF;
112 END;
113 $$  LANGUAGE PLPGSQL;
114
115 CREATE OR REPLACE FUNCTION vandelay._get_expr_push_jrow(
116     node vandelay.match_set_point,
117     tags_rstore HSTORE
118 ) RETURNS VOID AS $$
119 DECLARE
120     jrow        TEXT;
121     my_alias    TEXT;
122     op          TEXT;
123     tagkey      TEXT;
124     caseless    BOOL;
125 BEGIN
126     -- remember $1 is tags_rstore, and $2 is svf_rstore
127
128     caseless := FALSE;
129
130     IF node.tag IS NOT NULL THEN
131         caseless := (node.tag IN ('020', '022', '024'));
132         tagkey := node.tag;
133         IF node.subfield IS NOT NULL THEN
134             tagkey := tagkey || node.subfield;
135         END IF;
136     END IF;
137
138     IF node.negate THEN
139         IF caseless THEN
140             op := 'NOT LIKE';
141         ELSE
142             op := '<>';
143         END IF;
144     ELSE
145         IF caseless THEN
146             op := 'LIKE';
147         ELSE
148             op := '=';
149         END IF;
150     END IF;
151
152     my_alias := 'n' || node.id::TEXT;
153
154     jrow := 'LEFT JOIN (SELECT *, ' || node.quality ||
155         ' AS quality FROM metabib.';
156     IF node.tag IS NOT NULL THEN
157         jrow := jrow || 'full_rec) ' || my_alias || ' ON (' ||
158             my_alias || '.record = bre.id AND ' || my_alias || '.tag = ''' ||
159             node.tag || '''';
160         IF node.subfield IS NOT NULL THEN
161             jrow := jrow || ' AND ' || my_alias || '.subfield = ''' ||
162                 node.subfield || '''';
163         END IF;
164         jrow := jrow || ' AND (';
165
166         jrow := jrow || vandelay._node_tag_comparisons(caseless, my_alias, op, tags_rstore, tagkey);
167         jrow := jrow || '))';
168     ELSE    -- svf
169         jrow := jrow || 'record_attr) ' || my_alias || ' ON (' ||
170             my_alias || '.id = bre.id AND (' ||
171             my_alias || '.attrs->''' || node.svf ||
172             ''' ' || op || ' $2->''' || node.svf || '''))';
173     END IF;
174     INSERT INTO _vandelay_tmp_jrows (j) VALUES (jrow);
175 END;
176 $$ LANGUAGE PLPGSQL;
177
178 CREATE OR REPLACE FUNCTION vandelay._node_tag_comparisons(
179     caseless BOOLEAN,
180     my_alias TEXT,
181     op TEXT,
182     tags_rstore HSTORE,
183     tagkey TEXT
184 ) RETURNS TEXT AS $$
185 DECLARE
186     result  TEXT;
187     i       INT;
188     vals    TEXT[];
189 BEGIN
190     i := 1;
191     vals := tags_rstore->tagkey;
192     result := '';
193
194     WHILE TRUE LOOP
195         IF i > 1 THEN
196             IF vals[i] IS NULL THEN
197                 EXIT;
198             ELSE
199                 result := result || ' OR ';
200             END IF;
201         END IF;
202
203         IF caseless THEN
204             result := result || 'LOWER(' || my_alias || '.value) ' || op;
205         ELSE
206             result := result || my_alias || '.value ' || op;
207         END IF;
208
209         result := result || ' ' || COALESCE('''' || vals[i] || '''', 'NULL');
210
211         IF vals[i] IS NULL THEN
212             EXIT;
213         END IF;
214         i := i + 1;
215     END LOOP;
216
217     RETURN result;
218
219 END;
220 $$ LANGUAGE PLPGSQL;
221
222 -- drop old versions of these functions with fewer args
223 DROP FUNCTION vandelay.get_expr_from_match_set( INTEGER );
224 DROP FUNCTION vandelay.get_expr_from_match_set_point( vandelay.match_set_point );
225 DROP FUNCTION vandelay._get_expr_push_jrow( vandelay.match_set_point );
226
227 COMMIT;
228