]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/sql/Pg/upgrade/XXXX.function.browse_visibility_test.sql
32bdd9ef08a49998e18acaa273cdedc8e8b58a24
[Evergreen.git] / Open-ILS / src / sql / Pg / upgrade / XXXX.function.browse_visibility_test.sql
1 BEGIN;
2
3 CREATE OR REPLACE FUNCTION metabib.staged_browse(query text, fields integer[], context_org integer, context_locations integer[], staff boolean, browse_superpage_size integer, count_up_from_zero boolean, result_limit integer, next_pivot_pos integer)
4  RETURNS SETOF metabib.flat_browse_entry_appearance
5 AS $f$
6 DECLARE
7     curs                    REFCURSOR;
8     rec                     RECORD;
9     qpfts_query             TEXT;
10     aqpfts_query            TEXT;
11     afields                 INT[];
12     bfields                 INT[];
13     result_row              metabib.flat_browse_entry_appearance%ROWTYPE;
14     results_skipped         INT := 0;
15     row_counter             INT := 0;
16     row_number              INT;
17     slice_start             INT;
18     slice_end               INT;
19     full_end                INT;
20     all_records             BIGINT[];
21     all_brecords             BIGINT[];
22     all_arecords            BIGINT[];
23     superpage_of_records    BIGINT[];
24     superpage_size          INT;
25     c_tests                 TEXT := '';
26     b_tests                 TEXT := '';
27     c_orgs                  INT[];
28     unauthorized_entry      RECORD;
29 BEGIN
30     IF count_up_from_zero THEN
31         row_number := 0;
32     ELSE
33         row_number := -1;
34     END IF;
35
36     IF NOT staff THEN
37         SELECT x.c_attrs, x.b_attrs INTO c_tests, b_tests FROM asset.patron_default_visibility_mask() x;
38     END IF;
39
40     -- b_tests supplies its own query_int operator, c_tests does not
41     IF c_tests <> '' THEN c_tests := c_tests || '&'; END IF;
42
43     SELECT ARRAY_AGG(id) INTO c_orgs FROM actor.org_unit_descendants(context_org);
44
45     c_tests := c_tests || search.calculate_visibility_attribute_test('circ_lib',c_orgs)
46                || '&' || search.calculate_visibility_attribute_test('owning_lib',c_orgs);
47
48     PERFORM 1 FROM config.internal_flag WHERE enabled AND name = 'opac.located_uri.act_as_copy';
49     IF FOUND THEN
50         b_tests := b_tests || search.calculate_visibility_attribute_test(
51             'luri_org',
52             (SELECT ARRAY_AGG(id) FROM actor.org_unit_full_path(context_org) x)
53         );
54     ELSE
55         b_tests := b_tests || search.calculate_visibility_attribute_test(
56             'luri_org',
57             (SELECT ARRAY_AGG(id) FROM actor.org_unit_ancestors(context_org) x)
58         );
59     END IF;
60
61     IF context_locations THEN
62         IF c_tests <> '' THEN c_tests := c_tests || '&'; END IF;
63         c_tests := c_tests || search.calculate_visibility_attribute_test('location',context_locations);
64     END IF;
65
66     OPEN curs NO SCROLL FOR EXECUTE query;
67
68     LOOP
69         FETCH curs INTO rec;
70         IF NOT FOUND THEN
71             IF result_row.pivot_point IS NOT NULL THEN
72                 RETURN NEXT result_row;
73             END IF;
74             RETURN;
75         END IF;
76
77         --Is unauthorized?
78         SELECT INTO unauthorized_entry *
79         FROM metabib.browse_entry_simple_heading_map mbeshm
80         INNER JOIN authority.simple_heading ash ON ( mbeshm.simple_heading = ash.id )
81         INNER JOIN authority.control_set_authority_field acsaf ON ( acsaf.id = ash.atag )
82         JOIN authority.heading_field ahf ON (ahf.id = acsaf.heading_field)
83         WHERE mbeshm.entry = rec.id
84         AND   ahf.heading_purpose = 'variant';
85
86         -- Gather aggregate data based on the MBE row we're looking at now, authority axis
87         IF (unauthorized_entry.record IS NOT NULL) THEN
88             --unauthorized term belongs to an auth linked to a bib?
89             SELECT INTO all_arecords, result_row.sees, afields
90                     ARRAY_AGG(DISTINCT abl.bib),
91                     STRING_AGG(DISTINCT abl.authority::TEXT, $$,$$),
92                     ARRAY_AGG(DISTINCT map.metabib_field)
93             FROM authority.bib_linking abl
94             INNER JOIN authority.control_set_auth_field_metabib_field_map_refs map ON (
95                     map.authority_field = unauthorized_entry.atag
96                     AND map.metabib_field = ANY(fields)
97             )
98             WHERE abl.authority = unauthorized_entry.record;
99         ELSE
100             --do usual procedure
101             SELECT INTO all_arecords, result_row.sees, afields
102                     ARRAY_AGG(DISTINCT abl.bib), -- bibs to check for visibility
103                     STRING_AGG(DISTINCT aal.source::TEXT, $$,$$), -- authority record ids
104                     ARRAY_AGG(DISTINCT map.metabib_field) -- authority-tag-linked CMF rows
105
106             FROM  metabib.browse_entry_simple_heading_map mbeshm
107                     JOIN authority.simple_heading ash ON ( mbeshm.simple_heading = ash.id )
108                     JOIN authority.authority_linking aal ON ( ash.record = aal.source )
109                     JOIN authority.bib_linking abl ON ( aal.target = abl.authority )
110                     JOIN authority.control_set_auth_field_metabib_field_map_refs map ON (
111                         ash.atag = map.authority_field
112                         AND map.metabib_field = ANY(fields)
113                     )
114                     JOIN authority.control_set_authority_field acsaf ON (
115                         map.authority_field = acsaf.id
116                     )
117                     JOIN authority.heading_field ahf ON (ahf.id = acsaf.heading_field)
118               WHERE mbeshm.entry = rec.id
119               AND   ahf.heading_purpose = 'variant';
120
121         END IF;
122
123         -- Gather aggregate data based on the MBE row we're looking at now, bib axis
124         SELECT INTO all_brecords, result_row.authorities, bfields
125                 ARRAY_AGG(DISTINCT source),
126                 STRING_AGG(DISTINCT authority::TEXT, $$,$$),
127                 ARRAY_AGG(DISTINCT def)
128           FROM  metabib.browse_entry_def_map
129           WHERE entry = rec.id
130                 AND def = ANY(fields);
131
132         SELECT INTO result_row.fields STRING_AGG(DISTINCT x::TEXT, $$,$$) FROM UNNEST(afields || bfields) x;
133
134         result_row.sources := 0;
135         result_row.asources := 0;
136
137         -- Bib-linked vis checking
138         IF ARRAY_UPPER(all_brecords,1) IS NOT NULL THEN
139
140             SELECT  INTO result_row.sources COUNT(DISTINCT b.id)
141               FROM  biblio.record_entry b
142                     JOIN asset.copy_vis_attr_cache acvac ON (acvac.record = b.id)
143               WHERE b.id = ANY(all_brecords[1:browse_superpage_size])
144                     AND (
145                         acvac.vis_attr_vector @@ c_tests::query_int
146                         OR b.vis_attr_vector @@ b_tests::query_int
147                     );
148
149             result_row.accurate := TRUE;
150
151         END IF;
152
153         -- Authority-linked vis checking
154         IF ARRAY_UPPER(all_arecords,1) IS NOT NULL THEN
155
156             SELECT  INTO result_row.asources COUNT(DISTINCT b.id)
157               FROM  biblio.record_entry b
158                     JOIN asset.copy_vis_attr_cache acvac ON (acvac.record = b.id)
159               WHERE b.id = ANY(all_arecords[1:browse_superpage_size])
160                     AND (
161                         acvac.vis_attr_vector @@ c_tests::query_int
162                         OR b.vis_attr_vector @@ b_tests::query_int
163                     );
164
165             result_row.aaccurate := TRUE;
166
167         END IF;
168
169         IF result_row.sources > 0 OR result_row.asources > 0 THEN
170
171             -- The function that calls this function needs row_number in order
172             -- to correctly order results from two different runs of this
173             -- functions.
174             result_row.row_number := row_number;
175
176             -- Now, if row_counter is still less than limit, return a row.  If
177             -- not, but it is less than next_pivot_pos, continue on without
178             -- returning actual result rows until we find
179             -- that next pivot, and return it.
180
181             IF row_counter < result_limit THEN
182                 result_row.browse_entry := rec.id;
183                 result_row.value := rec.value;
184
185                 RETURN NEXT result_row;
186             ELSE
187                 result_row.browse_entry := NULL;
188                 result_row.authorities := NULL;
189                 result_row.fields := NULL;
190                 result_row.value := NULL;
191                 result_row.sources := NULL;
192                 result_row.sees := NULL;
193                 result_row.accurate := NULL;
194                 result_row.aaccurate := NULL;
195                 result_row.pivot_point := rec.id;
196
197                 IF row_counter >= next_pivot_pos THEN
198                     RETURN NEXT result_row;
199                     RETURN;
200                 END IF;
201             END IF;
202
203             IF count_up_from_zero THEN
204                 row_number := row_number + 1;
205             ELSE
206                 row_number := row_number - 1;
207             END IF;
208
209             -- row_counter is different from row_number.
210             -- It simply counts up from zero so that we know when
211             -- we've reached our limit.
212             row_counter := row_counter + 1;
213         END IF;
214     END LOOP;
215 END;
216 $f$ LANGUAGE plpgsql ROWS 10;
217
218 COMMIT;
219