-- ----------------------------------------------------
-- XXX TODO From here down, add this to stock SQL files
--- The following view supports checking for visibility for OPAC browse.
-CREATE OR REPLACE VIEW asset.visible_holdings AS
-SELECT
- bre.id AS record,
- COALESCE(
- aovc.circ_lib, acn_for_uri_map.owning_lib, acp_for_peer_bibs.circ_lib
- ) AS ou,
- COALESCE(aovc_acp.location, acp_for_peer_bibs.location) AS copy_location
-FROM biblio.record_entry bre
-LEFT JOIN asset.opac_visible_copies aovc
- ON (aovc.record = bre.id)
-LEFT JOIN asset.copy aovc_acp
- ON (aovc.copy_id = aovc_acp.id)
-LEFT JOIN asset.call_number acn_for_uri_map
- ON (acn_for_uri_map.record = aovc.record)
-LEFT JOIN asset.uri_call_number_map aucnm
- ON (aucnm.call_number = acn_for_uri_map.id)
-LEFT JOIN asset.uri auri
- ON (aucnm.uri = auri.id)
-LEFT JOIN biblio.peer_bib_copy_map bpbcm
- ON (bpbcm.peer_record = bre.id)
-LEFT JOIN asset.copy acp_for_peer_bibs
- ON (bpbcm.target_copy = acp_for_peer_bibs.id )
-LEFT JOIN asset.copy_location peer_copy_loc
- ON (peer_copy_loc.id = acp_for_peer_bibs.location )
-LEFT JOIN config.copy_status peer_copy_status
- ON (peer_copy_status.id = acp_for_peer_bibs.status)
-WHERE
- NOT bre.deleted AND
- COALESCE(auri.active, TRUE) AND
- NOT COALESCE(acp_for_peer_bibs.deleted, FALSE) AND
- COALESCE(
- acp_for_peer_bibs.opac_visible,
- peer_copy_loc.opac_visible,
- peer_copy_status.opac_visible,
- TRUE -- URIs and things on aovc are already known to be visible
- )
-UNION
-SELECT
- bre.id AS record,
- aou.id AS ou,
- NULL AS copy_location
-FROM biblio.record_entry bre
-INNER JOIN config.bib_source cbs
- ON (cbs.id = bre.source AND cbs.transcendant)
-INNER JOIN actor.org_unit aou ON (true)
-WHERE NOT bre.deleted ;
-
--- This view supports checking for holdings in scope for staff browse.
-
-CREATE OR REPLACE VIEW asset.staff_holdings AS
-SELECT
- bre.id AS record,
- COALESCE(
- acp.circ_lib, acn_for_uri_map.owning_lib, acp_for_peer_bibs.circ_lib
- ) AS ou,
- COALESCE(acp.location, acp_for_peer_bibs.location) AS copy_location
-FROM biblio.record_entry bre
-LEFT JOIN asset.call_number acn
- ON (acn.record = bre.id)
-LEFT JOIN asset.copy acp
- ON (acp.call_number = acn.id)
-LEFT JOIN asset.call_number acn_for_uri_map
- ON (acn_for_uri_map.record = bre.id)
-LEFT JOIN asset.uri_call_number_map aucnm
- ON (aucnm.call_number = acn_for_uri_map.id)
-LEFT JOIN asset.uri auri
- ON (aucnm.uri = auri.id)
-LEFT JOIN biblio.peer_bib_copy_map bpbcm
- ON (bpbcm.peer_record = bre.id)
-LEFT JOIN asset.copy acp_for_peer_bibs
- ON (bpbcm.target_copy = acp_for_peer_bibs.id )
-LEFT JOIN asset.copy_location peer_copy_loc
- ON (peer_copy_loc.id = acp_for_peer_bibs.location )
-LEFT JOIN config.copy_status peer_copy_status
- ON (peer_copy_status.id = acp_for_peer_bibs.status)
-WHERE
- NOT bre.deleted AND
- COALESCE(auri.active, TRUE) AND
- NOT COALESCE(acp_for_peer_bibs.deleted, FALSE)
-UNION
-SELECT
- bre.id AS record,
- aou.id AS ou,
- NULL AS copy_location
-FROM biblio.record_entry bre
-INNER JOIN config.bib_source cbs
- ON (cbs.id = bre.source AND cbs.transcendant)
-INNER JOIN actor.org_unit aou ON (true)
-WHERE NOT bre.deleted ;
ALTER TABLE metabib.browse_entry ADD COLUMN sort_value TEXT;
CREATE OR REPLACE FUNCTION metabib.browse_entry_sort_value()
-- indices.
-- CREATE INDEX CONCURRENTLY browse_entry_sort_value_idx_desc
--- ON metabib.browse_entry USING BTREE (sort_value DESC);
+-- ON metabib.browse_entry USING BTREE (sort_value DESC);
CREATE TYPE metabib.flat_browse_entry_appearance AS (
browse_entry BIGINT,
);
-CREATE OR REPLACE FUNCTION metabib._browse_joins_and_where(
+CREATE OR REPLACE FUNCTION metabib.browse_pivot(
search_field INT[],
- browse_term TEXT,
- context_org INT DEFAULT NULL,
- context_loc_group INT DEFAULT NULL,
- staff BOOL DEFAULT FALSE
-) RETURNS TEXT[] AS $p$
-DECLARE
- joins TEXT;
- where_clause TEXT;
- scope_test_view TEXT;
+ browse_term TEXT
+) RETURNS SETOF TEXT AS $p$
BEGIN
- joins := '
+ RETURN QUERY EXECUTE 'SELECT mbe.sort_value FROM metabib.browse_entry mbe
JOIN metabib.browse_entry_def_map mbedm ON (
mbedm.entry = mbe.id AND
mbedm.def = ANY(' || quote_literal(search_field) || ')
- ) ';
- where_clause := '';
-
- IF staff THEN
- scope_test_view := 'asset.staff_holdings';
- ELSE
- scope_test_view := 'asset.visible_holdings';
- END IF;
-
- IF context_org IS NOT NULL OR context_loc_group IS NOT NULL THEN
-
- joins := joins || ' JOIN ' || scope_test_view ||
- ' scope_test ON (scope_test.record = mbedm.source) ';
-
- IF context_org IS NOT NULL THEN
- where_clause := where_clause ||
- 'scope_test.ou IN (
- SELECT id FROM actor.org_unit_descendants(' ||
- context_org || ')) AND ';
- END IF;
-
- IF context_loc_group IS NOT NULL THEN
- where_clause := where_clause ||
- '(scope_test.copy_location IS NULL OR
- scope_test.copy_location IN (SELECT location FROM asset.copy_location_group_map WHERE lgroup = ' ||
- context_loc_group || ')) AND ';
- END IF;
- END IF;
-
- RETURN ARRAY[joins, where_clause];
-END;
-
-$p$ LANGUAGE PLPGSQL;
-
-CREATE OR REPLACE FUNCTION metabib.browse_pivot(
- search_field INT[],
- browse_term TEXT,
- context_org INT DEFAULT NULL,
- context_loc_group INT DEFAULT NULL
-) RETURNS TEXT AS $p$
-DECLARE
- joins TEXT;
- where_clause TEXT;
- joins_and_where TEXT[];
- result TEXT;
-BEGIN
- joins_and_where := metabib._browse_joins_and_where(
- search_field, browse_term, context_org, context_loc_group
- );
-
- joins := joins_and_where[1];
- where_clause := joins_and_where[2];
-
- EXECUTE 'SELECT mbe.sort_value FROM metabib.browse_entry mbe ' ||
- joins || 'WHERE ' || where_clause ||
- ' mbe.sort_value >= public.search_normalize(' ||
+ )
+ WHERE mbe.sort_value >= public.search_normalize(' ||
quote_literal(browse_term) ||
- ') ORDER BY mbe.sort_value LIMIT 1 ' INTO result;
-
- RETURN result; -- note, can be NULL
+ ') ORDER BY mbe.sort_value LIMIT 1 ';
END;
$p$ LANGUAGE PLPGSQL;
result_offset INT DEFAULT 0 -- Can be negative!
) RETURNS SETOF metabib.flat_browse_entry_appearance AS $p$
DECLARE
- joins TEXT;
- where_clause TEXT;
- joins_and_where TEXT[];
- result_query TEXT;
+ inner_query TEXT;
+ whole_query TEXT;
+ loc_query_part TEXT;
pivot_sort_value TEXT;
f RECORD;
r metabib.flat_browse_entry_appearance%ROWTYPE;
use_offset INT;
BEGIN
- pivot_sort_value := metabib.browse_pivot(
- search_field, browse_term, context_org, context_loc_group
- );
+ SELECT INTO pivot_sort_value * FROM metabib.browse_pivot(search_field, browse_term);
IF pivot_sort_value IS NULL THEN
RETURN;
END IF;
- joins_and_where := metabib._browse_joins_and_where(
- search_field, browse_term, context_org, context_loc_group
- );
-
- joins := joins_and_where[1];
- where_clause := joins_and_where[2];
-
- result_query :=
- 'SELECT mbe.id, mbe.value, mbe.sort_value,
- ARRAY_TO_STRING(
- (SELECT ARRAY_AGG(field) FROM (
- SELECT DISTINCT UNNEST(ARRAY_AGG(mbedm.def)) AS field
- ) y),
- $$,$$
- ) AS fields,
- ARRAY_TO_STRING(ARRAY_AGG(mbedm.authority), $$,$$) AS authorities,
- (SELECT COUNT(source) FROM (
- SELECT DISTINCT UNNEST(ARRAY_AGG(mbedm.source)) AS source
- ) x) sources
- FROM metabib.browse_entry mbe ' ||
- joins ||
- 'WHERE ' || where_clause;
+ inner_query := '
+ SELECT
+ mbe.id AS id,
+ (SELECT ARRAY_AGG(src) FROM (
+ SELECT DISTINCT UNNEST(ARRAY_AGG(mbedm.source)) AS src
+ ) ss) AS records,
+ 1 AS rel
+ FROM metabib.browse_entry mbe
+ JOIN metabib.browse_entry_def_map mbedm ON (
+ mbedm.entry = mbe.id AND
+ mbedm.def = ANY(' || quote_literal(search_field) || ')
+ )
+ WHERE ';
-- PostgreSQL is not magic. We can't actually pass a negative offset.
IF result_offset >= 0 THEN
use_offset := result_offset;
- result_query := result_query ||
+ inner_query := inner_query ||
' mbe.sort_value >= ' || quote_literal(pivot_sort_value) ||
- ' GROUP BY 1,2,3 ORDER BY mbe.sort_value ';
+ ' GROUP BY 1,3,mbe.sort_value ORDER BY mbe.sort_value ';
ELSE
-- Step 1 of 2 to deliver what the user wants with a negative offset:
- result_query := result_query ||
+ inner_query := inner_query ||
' mbe.sort_value < ' || quote_literal(pivot_sort_value) ||
- ' GROUP BY 1,2,3 ORDER BY mbe.sort_value DESC ';
+ ' GROUP BY 1,3,mbe.sort_value ORDER BY mbe.sort_value DESC ';
use_offset := ABS(result_offset) - result_limit;
IF use_offset < 0 THEN
END IF;
END IF;
- result_query := result_query ||
- ' LIMIT ' || result_limit || ' OFFSET ' || use_offset;
-
- IF result_offset < 0 THEN
- -- Step 2 of 2 to deliver what the user wants with a negative offset:
- result_query := 'SELECT * FROM (' || result_query ||
- ') x ORDER BY sort_value ASC'; -- Un-reverse the result set.
+-- XXX result_query := result_query ||
+-- XXX ' LIMIT ' || result_limit || ' OFFSET ' || use_offset;
+-- XXX
+-- XXX IF result_offset < 0 THEN
+-- XXX -- Step 2 of 2 to deliver what the user wants with a negative offset:
+-- XXX result_query := 'SELECT * FROM (' || result_query ||
+-- XXX ') x ORDER BY sort_value ASC'; -- Un-reverse the result set.
+-- XXX END IF;
+
+ IF context_loc_group IS NULL THEN
+ loc_query_part := 'NULL, ';
+ ELSE
+ loc_query_part :=
+ '(SELECT location FROM asset.copy_location_group_map WHERE
+ lgroup = ' || quote_literal(context_loc_group) || '), ';
END IF;
--- RAISE NOTICE 'query is { % }', result_query;
- FOR f IN EXECUTE result_query LOOP
+ whole_query := 'SELECT * FROM search.query_parser_fts(' ||
+ quote_literal(context_org) ||
+ ', NULL, ' ||
+ quote_literal(inner_query) ||
+ ', NULL, ' ||
+ loc_query_part ||
+ use_offset || ',' ||
+ result_limit ||
+ ', 10000,
+ NULL, ' ||
+ staff ||
+ ', FALSE)';
+ RAISE NOTICE 'query is { % }', whole_query;
+
+ FOR f IN EXECUTE whole_query LOOP
+ IF f.id IS NULL THEN
+ CONTINUE; -- We don't need the summary row
+ END IF;
r.browse_entry := f.id;
- r.value := f.value;
- r.fields := f.fields;
- r.authorities := f.authorities;
- r.sources := f.sources;
+ r.value := NULL; -- XXX rest of these are TODO
+ r.fields := NULL;
+ r.authorities := NULL;
+ r.sources := NULL;
RETURN NEXT r;
END LOOP;