Evergreen Database Schema - 3.10
Index of database - evergreen
- acq
- acq_lineitem_history
- acq_lineitem_lifecycle
- acq_purchase_order_history
- acq_purchase_order_lifecycle
- all_fund_allocation_total
- all_fund_combined_balance
- all_fund_encumbrance_total
- all_fund_spent_balance
- all_fund_spent_total
- cancel_reason
- claim
- claim_event
- claim_event_type
- claim_policy
- claim_policy_action
- claim_type
- currency_type
- debit_attribution
- distribution_formula
- distribution_formula_application
- distribution_formula_entry
- edi_account
- edi_attr
- edi_attr_set
- edi_attr_set_map
- edi_message
- exchange_rate
- fiscal_calendar
- fiscal_year
- fund
- fund_allocation
- fund_allocation_percent
- fund_allocation_total
- fund_combined_balance
- fund_debit
- fund_debit_total
- fund_encumbrance_total
- fund_spent_balance
- fund_spent_total
- fund_tag
- fund_tag_map
- fund_transfer
- funding_source
- funding_source_allocation_total
- funding_source_balance
- funding_source_credit
- funding_source_credit_total
- invoice
- invoice_entry
- invoice_item
- invoice_item_type
- invoice_method
- invoice_payment_method
- li_state_label
- lineitem
- lineitem_alert_text
- lineitem_attr
- lineitem_attr_definition
- lineitem_detail
- lineitem_generated_attr_definition
- lineitem_local_attr_definition
- lineitem_marc_attr_definition
- lineitem_note
- lineitem_provider_attr_definition
- lineitem_summary
- lineitem_usr_attr_definition
- ordered_funding_source_credit
- picklist
- po_item
- po_note
- po_state_label
- provider
- provider_address
- provider_contact
- provider_contact_address
- provider_holding_subfield_map
- provider_note
- purchase_order
- serial_claim
- serial_claim_event
- shipment_notification
- shipment_notification_entry
- user_request
- user_request_status_type
- user_request_type
- attribute_debits()
- audit_acq_lineitem_func()
- audit_acq_purchase_order_func()
- copy_fund_tags(new_fund_id integer, old_fund_id integer)
- create_acq_auditor(tbl text, sch text)
- create_acq_func(tbl text, sch text)
- create_acq_history(tbl text, sch text)
- create_acq_lifecycle(tbl text, sch text)
- create_acq_seq(tbl text, sch text)
- create_acq_update_trigger(tbl text, sch text)
- exchange_ratio(text, text, numeric)
- exchange_ratio(to_ex text, from_ex text)
- extract_holding_attr_table(tag integer, lineitem text)
- extract_provider_holding_data(lineitem_i integer)
- fap_limit_100()
- find_bad_fy()
- fund_alloc_percent_val()
- po_org_name_date_unique()
- propagate_funds_by_org_tree(include_desc integer, org_unit_id integer, user_id integer, old_year boolean)
- propagate_funds_by_org_unit(org_unit_id integer, user_id integer, old_year integer)
- purchase_order_name_default()
- rollover_funds_by_org_tree(include_desc integer, encumb_only integer, org_unit_id integer, user_id boolean, old_year boolean)
- rollover_funds_by_org_unit(encumb_only integer, org_unit_id integer, user_id integer, old_year boolean)
- transfer_fund(xfer_note integer, user_id numeric, new_amount integer, new_fund numeric, old_amount integer, old_fund text)
- action
- aged_circulation
- aged_hold_request
- all_circulation
- all_circulation_combined_types
- all_circulation_slim
- all_hold_request
- archive_actor_stat_cat
- archive_asset_stat_cat
- batch_hold_event
- batch_hold_event_map
- billable_circulations
- circulation
- circulation_limit_group_map
- curbside
- emergency_closing
- emergency_closing_circulation
- emergency_closing_hold
- emergency_closing_reservation
- emergency_closing_status
- fieldset
- fieldset_col_val
- fieldset_group
- hold_copy_map
- hold_notification
- hold_request
- hold_request_cancel_cause
- hold_request_note
- hold_transit_copy
- in_house_use
- non_cat_in_house_use
- non_cataloged_circulation
- open_circulation
- reservation_transit_copy
- survey
- survey_answer
- survey_question
- survey_response
- transit_copy
- unfulfilled_hold_innermost_loop
- unfulfilled_hold_list
- unfulfilled_hold_loops
- unfulfilled_hold_max_loop
- unfulfilled_hold_min_loop
- usr_circ_history
- age_circ_on_delete()
- age_hold_on_delete()
- age_parent_circ_on_delete()
- all_circ_chain(ctx_circ_id integer)
- apply_fieldset(query integer, pkey_name text, table_name text, fieldset_id text)
- archive_stat_cats()
- circ_chain(ctx_circ_id bigint)
- circulation_claims_returned()
- copy_calculated_proximity(vacl_ol integer, vacn_ol integer, vacp_cm integer, vacp_cl text, request integer, pickup integer)
- copy_related_hold_stats(copy_id bigint)
- copy_transit_is_unique()
- emergency_closing_stage_1(e_closing integer)
- emergency_closing_stage_2_circ(circ_closing_entry integer)
- emergency_closing_stage_2_hold(hold_closing_entry integer)
- emergency_closing_stage_2_reservation(res_closing_entry integer)
- fill_circ_copy_location()
- find_circ_matrix_matchpoint(renewal integer, match_user bigint, match_item integer, context_ou boolean)
- find_circ_matrix_matchpoint(renewal integer, user_object asset.copy, item_object actor.usr, context_ou boolean)
- find_hold_matrix_matchpoint(match_requestor integer, match_user integer, match_item bigint, request_ou integer, pickup_ou integer)
- hold_copy_calculated_proximity(copy_context_ou integer, acp_id bigint, ahr_id integer)
- hold_copy_calculated_proximity_update()
- hold_request_clear_map()
- hold_request_permit_test(match_requestor integer, match_user integer, match_item bigint, request_ou integer, pickup_ou integer)
- hold_request_permit_test(retargetting integer, match_requestor integer, match_user bigint, match_item integer, request_ou integer, pickup_ou boolean)
- hold_request_regen_copy_maps(copy_ids integer, hold_id integer[])
- hold_retarget_permit_test(match_requestor integer, match_user integer, match_item bigint, request_ou integer, pickup_ou integer)
- item_user_circ_test(integer, bigint, integer)
- item_user_circ_test(renewal integer, match_user bigint, match_item integer, circ_ou boolean)
- item_user_renew_test(integer, bigint, integer)
- link_circ_limit_groups(bigint, integer[])
- maintain_usr_circ_history()
- purge_circulations()
- purge_holds()
- push_circ_due_time()
- summarize_all_circ_chain(ctx_circ_id integer)
- summarize_circ_chain(ctx_circ_id bigint)
- survey_response_answer_date_fixup()
- usr_visible_holds(usr_id integer)
- action_trigger
- alternate_template
- cleanup
- collector
- environment
- event
- event_def_group
- event_def_group_member
- event_definition
- event_output
- event_params
- hook
- reactor
- validator
- check_valid_retention_interval()
- purge_events()
- actor
- address_alert
- card
- copy_alert_suppress
- hours_of_operation
- org_address
- org_lasso
- org_lasso_map
- org_unit
- org_unit_closed
- org_unit_custom_tree
- org_unit_custom_tree_node
- org_unit_proximity
- org_unit_proximity_adjustment
- org_unit_setting
- org_unit_type
- passwd
- passwd_type
- search_filter_group
- search_filter_group_entry
- search_query
- stat_cat
- stat_cat_entry
- stat_cat_entry_default
- stat_cat_entry_usr_map
- stat_cat_sip_fields
- toolbar
- usr
- usr_activity
- usr_address
- usr_message
- usr_message_limited
- usr_message_penalty
- usr_org_unit_opt_in
- usr_password_reset
- usr_privacy_waiver
- usr_saved_search
- usr_setting
- usr_standing_penalty
- workstation
- workstation_setting
- address_alert_matches(billing_address integer, mailing_address text, post_code text, country text, state text, county text, city text, street2 text, street1 boolean, org_unit boolean)
- approve_pending_address(pending_id integer)
- au_updated()
- calculate_system_penalties(context_org integer, match_user integer)
- change_password(pw_type integer, new_pw text, user_id text)
- create_salt(pw_type text)
- crypt_pw_insert()
- crypt_pw_update()
- get_cascade_setting(workstation_id text, user_id integer, org_id integer, setting_name integer)
- get_cascade_setting_batch(workstation_id text[], user_id integer, org_id integer, setting_names integer)
- get_salt(pw_type integer, pw_usr text)
- insert_usr_activity(ehow integer, ewhat text, ewho text, usr text)
- migrate_passwd(pw_usr integer)
- org_unit_ancestor_at_depth(integer, integer)
- org_unit_ancestor_setting(org_id text, setting_name integer)
- org_unit_ancestor_setting_batch(setting_names integer, org_id text[])
- org_unit_ancestor_setting_batch_by_org(org_ids text, setting_name integer[])
- org_unit_ancestors(integer)
- org_unit_ancestors_distance(distance integer)
- org_unit_combined_ancestors(integer, integer)
- org_unit_common_ancestors(integer, integer)
- org_unit_descendants(integer)
- org_unit_descendants(integer, integer)
- org_unit_descendants_distance(distance integer)
- org_unit_full_path(integer)
- org_unit_full_path(integer, integer)
- org_unit_parent_protect()
- org_unit_prox_update()
- org_unit_proximity(integer, integer)
- org_unit_simple_path(integer, integer)
- permit_remoteauth(userid text, profile_name bigint)
- purge_usr_activity_by_type(act_type integer)
- restrict_usr_message_limited()
- set_passwd(new_salt integer, new_pass text, pw_type text, pw_usr text)
- stat_cat_check()
- user_ingest_name_keywords()
- usr_activity_get_type(ehow text, ewhat text, ewho text)
- usr_activity_transient_trg()
- usr_delete(dest_usr integer, src_usr integer)
- usr_merge(deactivate_cards integer, del_cards integer, del_addrs boolean, dest_usr boolean, src_usr boolean)
- usr_merge_rows(dest_usr text, src_usr text, col_name integer, table_name integer)
- usr_purge_data(specified_dest_usr integer, src_usr integer)
- verify_passwd(test_passwd integer, pw_type text, pw_usr text)
- asset
- active_copy_alert
- call_number
- call_number_class
- call_number_note
- call_number_prefix
- call_number_suffix
- copy
- copy_alert
- copy_inventory
- copy_location
- copy_location_group
- copy_location_group_map
- copy_location_order
- copy_note
- copy_part_map
- copy_tag
- copy_tag_copy_map
- copy_template
- copy_vis_attr_cache
- course_module_course
- course_module_course_materials
- course_module_course_users
- course_module_role
- course_module_term
- course_module_term_course_map
- latest_inventory
- stat_cat
- stat_cat_entry
- stat_cat_entry_copy_map
- stat_cat_entry_transparency_map
- stat_cat_sip_fields
- uri
- uri_call_number_map
- acp_created()
- acp_location_fixer()
- acp_status_changed()
- all_visible_flags()
- autogenerate_placeholder_barcode()
- bib_source_default()
- cache_copy_visibility()
- calculate_copy_visibility_attribute_set(copy_id bigint)
- check_delete_copy_location(acpl_id integer)
- circ_lib_default()
- copy_may_float_to_inventory_workstation()
- copy_state(cid bigint)
- invisible_orgs(otype text)
- label_normalizer()
- label_normalizer_dewey(text)
- label_normalizer_generic(text)
- label_normalizer_lc(text)
- location_default()
- location_group_default()
- luri_org_default()
- merge_record_assets(source_record bigint, target_record bigint)
- metarecord_copy_count(transcendant integer, unshadow bigint, available boolean)
- metarecord_has_holdable_copy(ou bigint, rid integer)
- normalize_affix_sortkey()
- opac_lasso_metarecord_copy_count(transcendant integer, unshadow bigint)
- opac_lasso_record_copy_count(transcendant integer, unshadow bigint)
- opac_ou_metarecord_copy_count(transcendant integer, unshadow bigint)
- opac_ou_record_copy_count(transcendant integer, unshadow bigint)
- owning_lib_default()
- patron_default_visibility_mask()
- record_copy_count(transcendant integer, unshadow bigint, available boolean)
- record_has_holdable_copy(ou bigint, rid integer)
- set_copy_tag_value()
- staff_lasso_metarecord_copy_count(transcendant integer, unshadow bigint)
- staff_lasso_record_copy_count(transcendant integer, unshadow bigint)
- staff_ou_metarecord_copy_count(transcendant integer, unshadow bigint)
- staff_ou_record_copy_count(transcendant integer, unshadow bigint)
- stat_cat_check()
- status_default()
- visible_orgs(otype text)
- auditor
- acq_fund_debit_history
- acq_fund_debit_lifecycle
- acq_invoice_entry_history
- acq_invoice_entry_lifecycle
- acq_invoice_history
- acq_invoice_item_history
- acq_invoice_item_lifecycle
- acq_invoice_lifecycle
- actor_org_unit_history
- actor_org_unit_lifecycle
- actor_usr_address_history
- actor_usr_address_lifecycle
- actor_usr_history
- actor_usr_lifecycle
- asset_call_number_history
- asset_call_number_lifecycle
- asset_copy_history
- asset_copy_lifecycle
- biblio_record_entry_history
- biblio_record_entry_lifecycle
- serial_unit_history
- serial_unit_lifecycle
- audit_acq_fund_debit_func()
- audit_acq_invoice_entry_func()
- audit_acq_invoice_func()
- audit_acq_invoice_item_func()
- audit_actor_org_unit_func()
- audit_actor_usr_address_func()
- audit_actor_usr_func()
- audit_asset_call_number_func()
- audit_asset_copy_func()
- audit_biblio_record_entry_func()
- audit_serial_unit_func()
- clear_audit_info()
- create_auditor(tbl text, sch text)
- create_auditor_func(tbl text, sch text)
- create_auditor_history(tbl text, sch text)
- create_auditor_lifecycle(tbl text, sch text)
- create_auditor_seq(tbl text, sch text)
- create_auditor_update_trigger(tbl text, sch text)
- fix_columns()
- get_audit_info()
- set_audit_info(integer, integer)
- update_auditors()
- authority
- authority_linking
- bib_linking
- browse_axis
- browse_axis_authority_field_map
- control_set
- control_set_auth_field_metabib_field_map_blind_main
- control_set_auth_field_metabib_field_map_blind_refs
- control_set_auth_field_metabib_field_map_blind_refs_only
- control_set_auth_field_metabib_field_map_main
- control_set_auth_field_metabib_field_map_refs
- control_set_auth_field_metabib_field_map_refs_only
- control_set_authority_field
- control_set_bib_field
- control_set_bib_field_metabib_field_map
- full_rec
- heading_field
- heading_field_norm_map
- rec_descriptor
- record_entry
- record_note
- simple_heading
- thesaurus
- tracing_links
- atag_authority_tags(atag text)
- atag_authority_tags_refs(atag text)
- atag_browse_center(thesauruses text, pagesize text, page integer, q integer, a text)
- atag_browse_center_refs(thesauruses text, pagesize text, page integer, q integer, a text)
- atag_browse_top(thesauruses text, pagesize text, page integer, q integer, a text)
- atag_browse_top_refs(thesauruses text, pagesize text, page integer, q integer, a text)
- atag_search_heading(thesauruses text, pagesize text, page integer, q integer, a text)
- atag_search_heading_refs(thesauruses text, pagesize text, page integer, q integer, a text)
- atag_search_rank(thesauruses text, pagesize text, page integer, q integer, a text)
- atag_search_rank_refs(thesauruses text, pagesize text, page integer, q integer, a text)
- axis_authority_tags(a text)
- axis_authority_tags_refs(a text)
- axis_browse_center(thesauruses text, pagesize text, page integer, q integer, a text)
- axis_browse_center_refs(thesauruses text, pagesize text, page integer, q integer, a text)
- axis_browse_top(thesauruses text, pagesize text, page integer, q integer, a text)
- axis_browse_top_refs(thesauruses text, pagesize text, page integer, q integer, a text)
- axis_search_heading(thesauruses text, pagesize text, page integer, q integer, a text)
- axis_search_heading_refs(thesauruses text, pagesize text, page integer, q integer, a text)
- axis_search_rank(thesauruses text, pagesize text, page integer, q integer, a text)
- axis_search_rank_refs(thesauruses text, pagesize text, page integer, q integer, a text)
- btag_authority_tags(btag text)
- btag_authority_tags_refs(btag text)
- btag_browse_center(thesauruses text, pagesize text, page integer, q integer, a text)
- btag_browse_center_refs(thesauruses text, pagesize text, page integer, q integer, a text)
- btag_browse_top(thesauruses text, pagesize text, page integer, q integer, a text)
- btag_browse_top_refs(thesauruses text, pagesize text, page integer, q integer, a text)
- btag_search_heading(thesauruses text, pagesize text, page integer, q integer, a text)
- btag_search_heading_refs(thesauruses text, pagesize text, page integer, q integer, a text)
- btag_search_rank(thesauruses text, pagesize text, page integer, q integer, a text)
- btag_search_rank_refs(thesauruses text, pagesize text, page integer, q integer, a text)
- calculate_authority_linking(rec_marc_xml bigint, rec_control_set integer, rec_id xml)
- extract_headings(restrict bigint, rid integer[])
- extract_headings(restrict text, marc integer[])
- extract_thesaurus(marcxml text)
- flatten_marc(rid bigint)
- generate_overlay_template(bigint)
- generate_overlay_template(source_xml text)
- indexing_ingest_or_delete()
- map_thesaurus_to_control_set()
- merge_records(source_record bigint, target_record bigint)
- normalize_heading(marcxml text)
- normalize_heading(no_thesaurus text, marcxml boolean)
- normalize_heading_for_upsert()
- propagate_changes(aid bigint)
- propagate_changes(bid bigint, aid bigint)
- reingest_authority_full_rec(auth_id bigint)
- reingest_authority_rec_descriptor(auth_id bigint)
- simple_heading_browse_center(thesauruses integer[], pagesize text, page integer, q integer, atag_list text)
- simple_heading_browse_top(thesauruses integer[], pagesize text, page integer, q integer, atag_list text)
- simple_heading_find_pivot(thesauruses integer[], q text, a text)
- simple_heading_search_heading(thesauruses integer[], pagesize text, page integer, q integer, atag_list text)
- simple_heading_search_rank(thesauruses integer[], pagesize text, page integer, q integer, atag_list text)
- simple_heading_set(marcxml text)
- simple_normalize_heading(marcxml text)
- biblio
- monograph_part
- peer_bib_copy_map
- peer_type
- record_entry
- record_note
- calculate_bib_visibility_attribute_set(force_source bigint, new_source integer, bib_id boolean)
- check_marcxml_well_formed()
- extract_fingerprint(marc text)
- extract_located_uris(editor_id bigint, marcxml text, bib_id integer)
- extract_metabib_field_entry(only_fields bigint, field_types text, default_joiner text[], rid integer[])
- extract_quality(best_type text, best_lang text, marc text)
- fingerprint_trigger()
- flatten_marc(rid bigint)
- indexing_ingest_or_delete()
- map_authority_linking(marc bigint, bibid text)
- marc21_extract_all_fixed_fields(rid bigint)
- marc21_extract_fixed_field(ff bigint, rid text)
- marc21_extract_fixed_field_list(ff bigint, rid text)
- marc21_physical_characteristics(rid bigint)
- next_autogen_tcn_value()
- normalize_biblio_monograph_part_sortkey()
- booking
- reservation
- reservation_attr_value_map
- resource
- resource_attr
- resource_attr_map
- resource_attr_value
- resource_type
- config
- audience_map
- barcode_completion
- best_hold_order
- bib_level_map
- bib_source
- biblio_fingerprint
- billing_type
- carousel_type
- circ_limit_group
- circ_limit_set
- circ_limit_set_circ_mod_map
- circ_limit_set_copy_loc_map
- circ_limit_set_group_map
- circ_matrix_limit_set_map
- circ_matrix_matchpoint
- circ_matrix_weights
- circ_modifier
- coded_value_map
- composite_attr_entry_definition
- copy_alert_type
- copy_status
- copy_tag_type
- db_patch_dependencies
- display_field_map
- filter_dialog_filter_set
- filter_dialog_interface
- floating_group
- floating_group_member
- geolocation_service
- global_flag
- hard_due_date
- hard_due_date_values
- hold_matrix_matchpoint
- hold_matrix_weights
- hold_type
- i18n_core
- i18n_locale
- identification_type
- idl_field_doc
- index_normalizer
- internal_flag
- item_form_map
- item_type_map
- language_map
- lit_form_map
- marc21_ff_pos_map
- marc21_physical_characteristic_subfield_map
- marc21_physical_characteristic_type_map
- marc21_physical_characteristic_value_map
- marc21_rec_type_map
- marc_field
- marc_field_for_ou
- marc_format
- marc_subfield
- marc_subfield_for_ou
- metabib_class
- metabib_class_ts_map
- metabib_field
- metabib_field_index_norm_map
- metabib_field_ts_map
- metabib_field_virtual_map
- metabib_search_alias
- net_access_level
- non_cataloged_type
- openathens_identity
- openathens_name_field
- openathens_uid_field
- org_unit_setting_type
- org_unit_setting_type_log
- print_template
- record_attr_definition
- record_attr_index_norm_map
- remote_account
- remoteauth_profile
- rule_age_hold_protect
- rule_circ_duration
- rule_max_fine
- rule_recurring_fine
- settings_group
- sms_carrier
- standing
- standing_penalty
- ts_config_list
- ui_staff_portal_page_entry
- ui_staff_portal_page_entry_type
- upgrade_log
- usr_activity_type
- usr_setting_type
- videorecording_format_map
- weight_assoc
- workstation_setting_type
- xml_transform
- z3950_attr
- z3950_index_field_map
- z3950_source
- z3950_source_credentials
- interval_to_seconds(interval_string text)
- interval_to_seconds(interval_val interval)
- ou_marc_fields(ou integer, marc_record_type config.marc_record_type, marc_format integer)
- ou_marc_subfields(ou integer, marc_record_type config.marc_record_type, marc_format integer)
- setting_is_user_or_ws()
- update_coded_value_map(add_only text, in_is_simple text, in_search_label text, in_opac_visible text, in_description boolean, in_value text, in_code boolean, in_ctype boolean)
- update_hard_due_dates()
- z3950_source_credentials_apply(passwd text, uname integer, org text, src text)
- z3950_source_credentials_lookup(owner text, source integer)
- container
- biblio_record_entry_bucket
- biblio_record_entry_bucket_item
- biblio_record_entry_bucket_item_note
- biblio_record_entry_bucket_note
- biblio_record_entry_bucket_type
- call_number_bucket
- call_number_bucket_item
- call_number_bucket_item_note
- call_number_bucket_note
- call_number_bucket_type
- carousel
- carousel_org_unit
- copy_bucket
- copy_bucket_item
- copy_bucket_item_note
- copy_bucket_note
- copy_bucket_type
- user_bucket
- user_bucket_item
- user_bucket_item_note
- user_bucket_note
- user_bucket_type
- clear_all_expired_circ_history_items()
- clear_expired_circ_history_items(ac_usr integer)
- evergreen
- array_overlap_check()
- asset_copy_alert_copy_inh_fkey()
- asset_copy_inventory_copy_inh_fkey()
- asset_copy_note_owning_copy_inh_fkey()
- asset_copy_tag_copy_map_copy_inh_fkey()
- can_float(to_ou integer, from_ou integer, copy_floating_group integer)
- change_db_setting(settings text, setting_name text[])
- coded_value_map_normalizer(ctype text, input text)
- container_copy_bucket_item_target_copy_inh_fkey()
- could_be_serial_holding_code(text)
- display_field_force_nfc()
- escape_for_html(text)
- extract_marc_field(text, bigint, text)
- extract_marc_field(text, bigint, text, text)
- extract_marc_field_set(text, bigint, text, text)
- facet_force_nfc()
- fake_fkey_tgr()
- find_next_open_time(dow_count integer, initial_time timestamp with time zone, hourly boolean, initial time without time zone, circ_lib integer)
- force_unicode_normal_form(form text, string text)
- generic_map_normalizer(text, text)
- get_barcodes(in_barcode integer, type text, select_ou text)
- get_locale_name(description text)
- is_json(text)
- levenshtein_damerau_edistance( text, b text, a integer)
- limit_oustl()
- located_uris(rank bigint, label_sortkey integer, name integer)
- located_uris(rank bigint[], label_sortkey integer, name integer)
- located_uris_as_uris(pref_lib bigint, ouid integer, bibid integer)
- lowercase(text)
- lpad_number_substrings(text, text, integer)
- maintain_901()
- maintain_control_numbers()
- marc_to(xfrm text, marc text)
- oils_i18n_code_tracking()
- oils_i18n_gettext(integer, text, text, text)
- oils_i18n_gettext(text, text, text, text)
- oils_i18n_id_tracking()
- oils_i18n_update_apply(hint text, new_ident text, old_ident text)
- oils_i18n_xlate(raw_locale text, keyvalue text, identcol text, keycol text, keyclass text, keytable text)
- oils_json_to_text(text)
- oils_text_as_bytea(text)
- oils_xpath(text, text)
- oils_xpath(text, text, text[])
- oils_xpath_string(text, text)
- oils_xpath_string(text, text, anyarray)
- oils_xpath_string(text, text, text)
- oils_xpath_string(text, text, text, anyarray)
- oils_xpath_table(criteria text, xpaths text, relation_name text, document_field text, key text)
- oils_xpath_tag_to_table(xpaths text, tag text, marc text[])
- oils_xslt_process(text, text)
- org_top()
- ous_change_log()
- ous_delete_log()
- pg_statistics(frequency text, element text)
- protect_reserved_rows_from_delete()
- query_int_wrapper(integer[], text)
- qwerty_keyboard_distance(b text, a text)
- qwerty_keyboard_distance_match(b text, a text)
- rank_cp(copy asset.copy)
- rank_cp(copy_id bigint)
- rank_ou(plon integer, plat integer, pref_lib integer, search_lib double precision, lib double precision)
- rank_ou(pref_lib integer, search_lib integer, lib integer)
- ranked_volumes(rank bigint, label_sortkey integer, name integer, id public.hstore, includes public.hstore, pref_lib integer, soffset text[])
- ranked_volumes(rank bigint[], label_sortkey integer, name integer, id public.hstore, includes public.hstore, pref_lib integer, soffset text[])
- regexp_split_to_array(text, text)
- rel_bump(mults text[], bumps text, value text[], terms numeric[])
- tableoid2name(oid)
- text_array_merge_unique(text[], text[])
- unaccent_and_squash(arg text)
- upgrade_deps_block_check(my_applied_to text, my_db_patch text)
- upgrade_list_applied_deprecated(my_db_patch text)
- upgrade_list_applied_deprecates(my_db_patch text)
- upgrade_list_applied_superseded(my_db_patch text)
- upgrade_list_applied_supersedes(my_db_patch text)
- upgrade_verify_no_dep_conflicts(my_db_patch text)
- uppercase(text)
- vandelay_import_item_imported_as_inh_fkey()
- xml_escape(str text)
- xml_famous5_to_text(text)
- xml_pretty_print(input xml)
- z3950_attr_name_is_valid()
- extend_reporter
- metabib
- author_field_entry
- browse_entry
- browse_entry_def_map
- browse_entry_simple_heading_map
- combined_all_field_entry
- combined_author_field_entry
- combined_identifier_field_entry
- combined_keyword_field_entry
- combined_series_field_entry
- combined_subject_field_entry
- combined_title_field_entry
- composite_attr_id_map
- compressed_display_entry
- display_entry
- facet_entry
- flat_display_entry
- full_attr_id_map
- full_rec
- identifier_field_entry
- keyword_field_entry
- metarecord
- metarecord_source_map
- real_full_rec
- rec_descriptor
- record_attr
- record_attr_flat
- record_attr_id_map
- record_attr_vector_list
- record_sorter
- series_field_entry
- subject_field_entry
- title_field_entry
- uncontrolled_record_attr_value
- wide_display_entry
- autosuggest_prepare_tsquery(orig text)
- browse(result_limit integer[], pivot_id text, staff integer, context_loc_group integer, context_org boolean, browse_term bigint, search_field integer)
- browse(result_limit text, pivot_id text, staff integer, context_loc_group integer, context_org boolean, browse_term bigint, search_class integer)
- browse_authority_pivot(integer[], text)
- browse_authority_refs_pivot(integer[], text)
- browse_bib_pivot(integer[], text)
- browse_normalize(mapped_field text, facet_text integer)
- browse_pivot(integer[], text)
- compile_composite_attr(cattr_def text)
- compile_composite_attr(cattr_id integer)
- compile_composite_attr_cache_disable()
- compile_composite_attr_cache_init()
- compile_composite_attr_cache_invalidate()
- composite_attr_def_cache_inval_tgr()
- display_field_normalize_trigger()
- facet_normalize_trigger()
- reingest_metabib_field_entries(only_fields bigint, skip_search boolean, skip_browse boolean, skip_display boolean, skip_facet boolean, bib_id integer[])
- reingest_metabib_full_rec(bib_id bigint)
- reingest_record_attributes(rdeleted bigint, prmarc text[], pattr_list text, rid boolean)
- remap_metarecord_for_bib(retain_deleted bigint, bib_is_deleted text, fp boolean, bib_id boolean)
- search_class_to_registered_components(search_class text)
- staged_browse(next_pivot_pos text, result_limit integer[], count_up_from_zero integer, browse_superpage_size integer[], staff boolean, context_locations integer, context_org boolean, fields integer, query integer)
- suggest_browse_entries(match text, buoyant text, rank text, field_weight integer, field_match integer, buoyant_and_class_match integer)
- trim_trailing_punctuation(text)
- update_combined_index_vectors(bib_id bigint)
- money
- account_adjustment
- aged_billing
- aged_payment
- all_billings
- all_payments
- billable_xact
- billable_xact_summary
- billable_xact_summary_location_view
- billable_xact_with_void_summary
- billing
- bnm_desk_payment
- bnm_payment
- bnm_payment_view
- cash_payment
- cashdrawer_payment_view
- check_payment
- collections_tracker
- credit_card_payment
- credit_payment
- debit_card_payment
- desk_payment_view
- forgive_payment
- goods_payment
- grocery
- materialized_billable_xact_summary
- non_drawer_payment_view
- open_billable_xact_summary
- open_transaction_billing_summary
- open_transaction_billing_type_summary
- open_transaction_payment_summary
- open_usr_circulation_summary
- open_usr_summary
- open_with_balance_usr_summary
- payment
- payment_view
- payment_view_for_aging
- transaction_billing_summary
- transaction_billing_type_summary
- transaction_billing_with_void_summary
- transaction_payment_summary
- transaction_payment_with_void_summary
- usr_circulation_summary
- usr_summary
- work_payment
- age_billings_and_payments()
- age_billings_and_payments_for_xact(xact_id bigint)
- maintain_billing_ts()
- mat_summary_create()
- mat_summary_delete()
- mat_summary_update()
- materialized_summary_billing_add()
- materialized_summary_billing_del()
- materialized_summary_billing_update()
- materialized_summary_payment_add()
- materialized_summary_payment_del()
- materialized_summary_payment_update()
- oai
- authority
- biblio
- auth_is_visible_by_axis(ax bigint, auth text)
- bib_is_visible_at_org_by_copy(org bigint, bib integer)
- bib_is_visible_at_org_by_luri(org bigint, bib integer)
- bib_is_visible_by_source(src bigint, bib text)
- offline
- permission
- grp_penalty_threshold
- grp_perm_map
- grp_tree
- grp_tree_display_entry
- perm_list
- usr_grp_map
- usr_object_perm_map
- usr_perm_map
- usr_work_ou_map
- grp_ancestors(integer)
- grp_ancestors_distance(distance integer)
- grp_descendants(integer)
- grp_descendants_distance(distance integer)
- grp_tree_combined_ancestors(integer, integer)
- grp_tree_common_ancestors(integer, integer)
- grp_tree_full_path(integer)
- usr_can_grant_perm(target_ou integer, tperm text, iuser integer)
- usr_has_home_perm(target_ou integer, tperm text, iuser integer)
- usr_has_object_perm(integer, text, text, text)
- usr_has_object_perm(target_ou integer, obj_id text, obj_type text, tperm text, iuser integer)
- usr_has_perm(integer, text, integer)
- usr_has_perm_at(perm_code integer, user_id text)
- usr_has_perm_at_all(perm_code integer, user_id text)
- usr_has_perm_at_all_nd(perm_code integer, user_id text)
- usr_has_perm_at_nd(perm_code integer, user_id text)
- usr_has_work_perm(target_ou integer, tperm text, iuser integer)
- usr_perms(integer)
- public
- _int_contained(integer[], integer[])
- _int_contained_joinsel(internal, oid, internal, smallint, internal)
- _int_contained_sel(internal, oid, internal, integer)
- _int_contains(integer[], integer[])
- _int_contains_joinsel(internal, oid, internal, smallint, internal)
- _int_contains_sel(internal, oid, internal, integer)
- _int_different(integer[], integer[])
- _int_inter(integer[], integer[])
- _int_matchsel(internal, oid, internal, integer)
- _int_overlap(integer[], integer[])
- _int_overlap_joinsel(internal, oid, internal, smallint, internal)
- _int_overlap_sel(internal, oid, internal, integer)
- _int_same(integer[], integer[])
- _int_union(integer[], integer[])
- _intbig_in(cstring)
- _intbig_out(public.intbig_gkey)
- agg_text(text)
- akeys(public.hstore)
- approximate_date(text, text)
- approximate_high_date(text)
- approximate_low_date(text)
- armor(bytea)
- armor(bytea, text[], text[])
- avals(public.hstore)
- boolop(integer[], public.query_int)
- bqarr_in(cstring)
- bqarr_out(public.query_int)
- call_number_dewey(text)
- call_number_dewey(text, integer)
- cleanup_acq_marc()
- content_or_null(text)
- crypt(text, text)
- cube(double precision)
- cube(double precision, double precision)
- cube(double precision[])
- cube(double precision[], double precision[])
- cube(public.cube, double precision)
- cube(public.cube, double precision, double precision)
- cube_cmp(public.cube, public.cube)
- cube_contained(public.cube, public.cube)
- cube_contains(public.cube, public.cube)
- cube_coord(public.cube, integer)
- cube_coord_llur(public.cube, integer)
- cube_dim(public.cube)
- cube_distance(public.cube, public.cube)
- cube_enlarge(public.cube, double precision, integer)
- cube_eq(public.cube, public.cube)
- cube_ge(public.cube, public.cube)
- cube_gt(public.cube, public.cube)
- cube_in(cstring)
- cube_inter(public.cube, public.cube)
- cube_is_point(public.cube)
- cube_le(public.cube, public.cube)
- cube_ll_coord(public.cube, integer)
- cube_lt(public.cube, public.cube)
- cube_ne(public.cube, public.cube)
- cube_out(public.cube)
- cube_overlap(public.cube, public.cube)
- cube_size(public.cube)
- cube_subset(public.cube, integer[])
- cube_union(public.cube, public.cube)
- cube_ur_coord(public.cube, integer)
- dearmor(text)
- decrypt(bytea, bytea, text)
- decrypt_iv(bytea, bytea, bytea, text)
- defined(public.hstore, text)
- delete(public.hstore, public.hstore)
- delete(public.hstore, text)
- delete(public.hstore, text[])
- difference(text, text)
- digest(bytea, text)
- digest(text, text)
- distance_chebyshev(public.cube, public.cube)
- distance_taxicab(public.cube, public.cube)
- dmetaphone(text)
- dmetaphone_alt(text)
- each(value public.hstore)
- earth()
- earth_box(public.earth, double precision)
- earth_distance(public.earth, public.earth)
- encrypt(bytea, bytea, text)
- encrypt_iv(bytea, bytea, bytea, text)
- entityize(text)
- exist(public.hstore, text)
- exists_all(public.hstore, text[])
- exists_any(public.hstore, text[])
- extract_acq_marc_field(bigint, text, text)
- extract_acq_marc_field_set(bigint, text, text)
- fetchval(public.hstore, text)
- first(anyelement)
- first5(text)
- first_agg(anyelement, anyelement)
- first_word(text)
- force_to_isbn13(text)
- g_cube_compress(internal)
- g_cube_consistent(internal, public.cube, smallint, oid, internal)
- g_cube_decompress(internal)
- g_cube_distance(internal, public.cube, smallint, oid, internal)
- g_cube_penalty(internal, internal, internal)
- g_cube_picksplit(internal, internal)
- g_cube_same(public.cube, public.cube, internal)
- g_cube_union(internal, internal)
- g_int_compress(internal)
- g_int_consistent(internal, integer[], smallint, oid, internal)
- g_int_decompress(internal)
- g_int_penalty(internal, internal, internal)
- g_int_picksplit(internal, internal)
- g_int_same(integer[], integer[], internal)
- g_int_union(internal, internal)
- g_intbig_compress(internal)
- g_intbig_consistent(internal, integer[], smallint, oid, internal)
- g_intbig_decompress(internal)
- g_intbig_penalty(internal, internal, internal)
- g_intbig_picksplit(internal, internal)
- g_intbig_same(public.intbig_gkey, public.intbig_gkey, internal)
- g_intbig_union(internal, internal)
- gc_to_sec(double precision)
- gen_random_bytes(integer)
- gen_random_uuid()
- gen_salt(text)
- gen_salt(text, integer)
- geo_distance(point, point)
- ghstore_compress(internal)
- ghstore_consistent(internal, public.hstore, smallint, oid, internal)
- ghstore_decompress(internal)
- ghstore_in(cstring)
- ghstore_out(public.ghstore)
- ghstore_penalty(internal, internal, internal)
- ghstore_picksplit(internal, internal)
- ghstore_same(public.ghstore, public.ghstore, internal)
- ghstore_union(internal, internal)
- gin_consistent_hstore(internal, smallint, public.hstore, integer, internal, internal)
- gin_extract_hstore(public.hstore, internal)
- gin_extract_hstore_query(public.hstore, internal, smallint, internal, internal)
- gin_extract_query_trgm(text, internal, smallint, internal, internal, internal, internal)
- gin_extract_value_trgm(text, internal)
- gin_trgm_consistent(internal, smallint, text, integer, internal, internal, internal, internal)
- gin_trgm_triconsistent(internal, smallint, text, integer, internal, internal, internal)
- ginint4_consistent(internal, smallint, integer[], integer, internal, internal, internal, internal)
- ginint4_queryextract(integer[], internal, smallint, internal, internal, internal, internal)
- gtrgm_compress(internal)
- gtrgm_consistent(internal, text, smallint, oid, internal)
- gtrgm_decompress(internal)
- gtrgm_distance(internal, text, smallint, oid, internal)
- gtrgm_in(cstring)
- gtrgm_out(public.gtrgm)
- gtrgm_penalty(internal, internal, internal)
- gtrgm_picksplit(internal, internal)
- gtrgm_same(public.gtrgm, public.gtrgm, internal)
- gtrgm_union(internal, internal)
- hmac(bytea, bytea, text)
- hmac(text, text, text)
- hs_concat(public.hstore, public.hstore)
- hs_contained(public.hstore, public.hstore)
- hs_contains(public.hstore, public.hstore)
- hstore(record)
- hstore(text, text)
- hstore(text[])
- hstore(text[], text[])
- hstore_cmp(public.hstore, public.hstore)
- hstore_eq(public.hstore, public.hstore)
- hstore_ge(public.hstore, public.hstore)
- hstore_gt(public.hstore, public.hstore)
- hstore_hash(public.hstore)
- hstore_in(cstring)
- hstore_le(public.hstore, public.hstore)
- hstore_lt(public.hstore, public.hstore)
- hstore_ne(public.hstore, public.hstore)
- hstore_out(public.hstore)
- hstore_recv(internal)
- hstore_send(public.hstore)
- hstore_to_array(public.hstore)
- hstore_to_json(public.hstore)
- hstore_to_json_loose(public.hstore)
- hstore_to_jsonb(public.hstore)
- hstore_to_jsonb_loose(public.hstore)
- hstore_to_matrix(public.hstore)
- hstore_version_diag(public.hstore)
- icount(integer[])
- idx(integer[], integer)
- ingest_acq_marc()
- intarray_del_elem(integer[], integer)
- intarray_push_array(integer[], integer[])
- intarray_push_elem(integer[], integer)
- integer_or_null(text)
- intset(integer)
- intset_subtract(integer[], integer[])
- intset_union_elem(integer[], integer)
- isdefined(public.hstore, text)
- isexists(public.hstore, text)
- last(anyelement)
- last_agg(anyelement, anyelement)
- latitude(public.earth)
- left_trunc(text, integer)
- levenshtein(text, text)
- levenshtein(text, text, integer, integer, integer)
- levenshtein_less_equal(text, text, integer)
- levenshtein_less_equal(text, text, integer, integer, integer, integer)
- ll_to_earth(double precision, double precision)
- longitude(public.earth)
- lowercase(text)
- metaphone(text, integer)
- naco_normalize(text)
- naco_normalize(text, text)
- naco_normalize_keep_comma(text)
- non_filing_normalize(text, "char")
- normalize_space(text)
- oils_tsearch2()
- pgp_armor_headers(value text)
- pgp_key_id(bytea)
- pgp_pub_decrypt(bytea, bytea)
- pgp_pub_decrypt(bytea, bytea, text)
- pgp_pub_decrypt(bytea, bytea, text, text)
- pgp_pub_decrypt_bytea(bytea, bytea)
- pgp_pub_decrypt_bytea(bytea, bytea, text)
- pgp_pub_decrypt_bytea(bytea, bytea, text, text)
- pgp_pub_encrypt(text, bytea)
- pgp_pub_encrypt(text, bytea, text)
- pgp_pub_encrypt_bytea(bytea, bytea)
- pgp_pub_encrypt_bytea(bytea, bytea, text)
- pgp_sym_decrypt(bytea, text)
- pgp_sym_decrypt(bytea, text, text)
- pgp_sym_decrypt_bytea(bytea, text)
- pgp_sym_decrypt_bytea(bytea, text, text)
- pgp_sym_encrypt(text, text)
- pgp_sym_encrypt(text, text, text)
- pgp_sym_encrypt_bytea(bytea, text)
- pgp_sym_encrypt_bytea(bytea, text, text)
- populate_record(anyelement, public.hstore)
- querytree(public.query_int)
- rboolop(public.query_int, integer[])
- remove_commas(text)
- remove_diacritics(text)
- remove_paren_substring(text)
- remove_whitespace(text)
- right_trunc(text, integer)
- search_normalize(text)
- search_normalize(text, text)
- search_normalize_keep_comma(text)
- sec_to_gc(double precision)
- set_limit(real)
- show_limit()
- show_trgm(text)
- similarity(text, text)
- similarity_dist(text, text)
- similarity_op(text, text)
- skeys(public.hstore)
- slice(public.hstore, text[])
- slice_array(public.hstore, text[])
- sort(integer[])
- sort(integer[], text)
- sort_asc(integer[])
- sort_desc(integer[])
- soundex(text)
- split_date_range(text)
- subarray(integer[], integer)
- subarray(integer[], integer, integer)
- svals(public.hstore)
- tconvert(text, text)
- text_concat(text, text)
- text_soundex(text)
- translate_isbn1013(text)
- unaccent(regdictionary, text)
- unaccent(text)
- unaccent_init(internal)
- unaccent_lexize(internal, internal, internal, internal)
- uniq(integer[])
- uppercase(text)
- word_similarity(text, text)
- word_similarity_commutator_op(text, text)
- word_similarity_dist_commutator_op(text, text)
- word_similarity_dist_op(text, text)
- word_similarity_op(text, text)
- xml_encode_special_chars(text)
- xml_valid(text)
- xpath_bool(text, text)
- xpath_list(text, text)
- xpath_list(text, text, text)
- xpath_nodeset(text, text)
- xpath_nodeset(text, text, text)
- xpath_nodeset(text, text, text, text)
- xpath_number(text, text)
- xpath_string(text, text)
- xpath_table(text, text, text, text, text)
- xslt_process(text, text)
- xslt_process(text, text, text)
- query
- bind_variable
- case_branch
- datatype
- expr_xbet
- expr_xbind
- expr_xbool
- expr_xcase
- expr_xcast
- expr_xcol
- expr_xex
- expr_xfunc
- expr_xin
- expr_xisnull
- expr_xnull
- expr_xnum
- expr_xop
- expr_xser
- expr_xstr
- expr_xsubq
- expression
- from_relation
- function_param_def
- function_sig
- order_by_item
- query_sequence
- record_column
- select_item
- stored_query
- subfield
- rating
- badge
- badge_with_orgs
- popularity_parameter
- record_badge_score
- bib_pub_age(value integer)
- bib_record_age(value integer)
- checked_out_total_ratio(value integer)
- circs_over_time(value integer)
- copy_count(value integer)
- current_circ_count(value integer)
- current_hold_count(value integer)
- generic_fixed_rating_by_copy(value integer)
- generic_fixed_rating_by_copy_or_uri(value integer)
- generic_fixed_rating_by_uri(value integer)
- generic_fixed_rating_global(value integer)
- holds_filled_over_time(value integer)
- holds_holdable_ratio(value integer)
- holds_placed_over_time(value integer)
- holds_total_ratio(value integer)
- inhouse_over_time(value integer)
- org_unit_count(value integer)
- percent_time_circulating(value integer)
- precalc_attr_filter(attr_filter text)
- precalc_bibs_by_copy(badge_id integer)
- precalc_bibs_by_copy_or_uri(badge_id integer)
- precalc_bibs_by_uri(badge_id integer)
- precalc_circ_mod_filter(cm text)
- precalc_location_filter(loc integer)
- precalc_src_filter(src integer)
- recalculate_badge_score(setup_only integer, badge_id boolean)
- reporter
- asset_call_number_dewey
- circ_type
- completed_reports
- currently_running
- demographic
- hold_request_record
- materialized_simple_record
- old_super_simple_record
- output_folder
- overdue_circs
- overdue_reports
- pending_reports
- report
- report_folder
- schedule
- simple_record
- super_simple_record
- template
- template_folder
- xact_billing_totals
- xact_paid_totals
- disable_materialized_simple_record_trigger()
- enable_materialized_simple_record_trigger()
- hold_request_record_mapper()
- intersect_user_perm_ou(perm_code bigint, staff_id bigint, context_ou text)
- refresh_materialized_simple_record()
- simple_rec_delete(r_id bigint)
- simple_rec_trigger()
- simple_rec_update(deleted bigint, r_id boolean)
- simple_rec_update(r_id bigint)
- search
- best_tsconfig
- relevance_adjustment
- symspell_dictionary
- symspell_dictionary_updates
- calculate_visibility_attribute(attr integer, value text)
- calculate_visibility_attribute_list(value text, attr integer[])
- calculate_visibility_attribute_test(negate text, value integer[], attr boolean)
- disable_symspell_reification()
- enable_symspell_reification()
- facets_for_metarecord_set(count text[], value bigint[])
- facets_for_record_set(count text[], value bigint[])
- highlight_display_fields(delimiter bigint, maxfrags text, shortwords text, maxwords boolean, minwords integer, hl_all integer, css_class integer, tsq_map integer, rid text)
- highlight_display_fields_impl(delimiter bigint, maxfrags text, shortwords integer[], maxwords text, minwords boolean, hl_all integer, css_class integer, field_list integer, tsq integer, rid text)
- symspell_build_entries(include_phrases text, old_input text, source_class text, full_input boolean)
- symspell_build_raw_entry(maxed text, prefix_length text, no_limit boolean, source_class integer, raw_input integer)
- symspell_dictionary_full_reify()
- symspell_dictionary_reify()
- symspell_generate_edits(maxed text, dist integer, raw_word integer)
- symspell_lookup(kbdist_weight text, pg_trgm_weight text, soundex_weight integer, count_threshold boolean, xfer_case integer, verbosity integer, search_class integer, raw_input integer)
- symspell_maintain_entries()
- symspell_parse_words(phrase text)
- symspell_parse_words_distinct(phrase text)
- symspell_transfer_casing(withoutcase text, withcase text)
- serial
- any_summary
- basic_summary
- caption_and_pattern
- distribution
- distribution_note
- index_summary
- issuance
- item
- item_note
- materialized_holding_code
- pattern_template
- record_entry
- routing_list_user
- stream
- subscription
- subscription_note
- supplement_summary
- unit
- materialize_holding_code()
- pattern_templates_visible_to(org_unit integer)
- staging
- billing_address_stage
- card_stage
- mailing_address_stage
- setting_stage
- statcat_stage
- user_stage
- purge_pending_users()
- stats
- unapi
- bre_output_layout
- acl(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
- acn(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
- acnp(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
- acns(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
- acp(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
- acpn(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
- aou(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
- ascecm(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
- auri(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
- biblio_record_entry_feed(pref_lib bigint[], header_xml text, unapi_url text[], update_ts text, creator integer, description public.hstore, title public.hstore, include_xmlns boolean, soffset text, slimit text, depth text, org text, includes text, format xml, id_list integer)
- bmp(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
- bre(pref_lib bigint, include_xmlns text, soffset text, slimit text[], depth text, org integer, includes public.hstore, ename public.hstore, format boolean, obj_id integer)
- cbs(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
- ccs(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
- circ(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
- holdings_xml(pref_lib bigint, include_xmlns integer, soffset text, slimit integer, includes text[], depth public.hstore, org public.hstore, ouid boolean, bid integer)
- memoize(include_xmlns text, soffset bigint, slimit text, depth text, org text[], includes text, ename integer, format public.hstore, obj_id public.hstore, classname boolean)
- metabib_virtual_record_feed(pref_lib bigint[], header_xml text, unapi_url text[], update_ts text, creator integer, description public.hstore, title public.hstore, include_xmlns boolean, soffset text, slimit text, depth text, org text, includes text, format xml, id_list integer)
- mmr(pref_lib bigint, include_xmlns text, soffset text, slimit text[], depth text, org integer, includes public.hstore, ename public.hstore, format boolean, obj_id integer)
- mmr_holdings_xml(pref_lib bigint, include_xmlns integer, soffset text, slimit integer, includes text[], depth public.hstore, org public.hstore, ouid boolean, mid integer)
- mmr_mra(pref_lib bigint, include_xmlns text, soffset text, slimit text[], depth text, org integer, includes public.hstore, ename public.hstore, format boolean, obj_id integer)
- mra(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
- sbsum(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
- sdist(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
- siss(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
- sisum(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
- sitem(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
- sssum(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
- sstr(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
- ssub(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
- sunit(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
- url_verify
- session
- url
- url_selector
- url_verification
- verification_attempt
- extract_urls(item_id integer, session_id integer)
- ingest_url()
- parse_url(url_in text)
- vandelay
- authority_attr_definition
- authority_match
- authority_queue
- bib_attr_definition
- bib_match
- bib_queue
- import_bib_trash_fields
- import_bib_trash_group
- import_error
- import_item
- import_item_attr_definition
- match_set
- match_set_point
- match_set_quality
- merge_profile
- queue
- queued_authority_record
- queued_authority_record_attr
- queued_bib_record
- queued_bib_record_attr
- queued_record
- session_tracker
- _get_expr_push_jrow(auth_heading vandelay.match_set_point, tags_rstore public.hstore, node text)
- _get_expr_push_qrow(node vandelay.match_set_point)
- _get_expr_render_one(node vandelay.match_set_point)
- _node_tag_comparisons(tagkey boolean, tags_rstore text, op public.hstore, caseless text)
- add_field(field text, source_xml text, target_xml text)
- add_field(force_add text, field text, source_xml text, target_xml integer)
- auto_overlay_authority_queue(merge_profile_id bigint, queue_id integer)
- auto_overlay_authority_queue(queue_id bigint)
- auto_overlay_authority_record(merge_profile_id bigint, import_id integer)
- auto_overlay_authority_record_with_best(lwm_ratio_value_p bigint, merge_profile_id integer, import_id numeric)
- auto_overlay_bib_queue(merge_profile_id bigint, queue_id integer)
- auto_overlay_bib_queue(queue_id bigint)
- auto_overlay_bib_queue_with_best(lwm_ratio_value bigint, merge_profile_id integer, queue_id numeric)
- auto_overlay_bib_queue_with_best(merge_profile_id bigint, import_id integer)
- auto_overlay_bib_record(merge_profile_id bigint, import_id integer)
- auto_overlay_bib_record_with_best(lwm_ratio_value_p bigint, merge_profile_id integer, import_id numeric)
- auto_overlay_bib_record_with_best(merge_profile_id bigint, import_id integer)
- auto_overlay_org_unit_copies(lwm_ratio_value_p bigint, merge_profile_id integer, import_id numeric)
- cleanup_authority_marc()
- cleanup_bib_marc()
- compile_profile(incoming_xml text)
- extract_rec_attrs(attr_defs text, xml text[])
- extract_rec_attrs(xml text)
- find_bib_tcn_data(xml text)
- flatten_marc(marc text)
- flatten_marc_hstore(record_xml text)
- flay_marc(text)
- get_expr_from_match_set(auth_heading integer, tags_rstore public.hstore, match_set_id text)
- get_expr_from_match_set(tags_rstore integer, match_set_id public.hstore)
- get_expr_from_match_set_point(auth_heading vandelay.match_set_point, tags_rstore public.hstore, node text)
- ingest_authority_marc()
- ingest_bib_items()
- ingest_bib_marc()
- ingest_items(attr_def_id bigint, import_id bigint)
- marc21_extract_all_fixed_fields(use_default text, marc boolean)
- marc21_extract_fixed_field(use_default text, ff text, marc boolean)
- marc21_extract_fixed_field_list(use_default text, ff text, marc boolean)
- marc21_physical_characteristics(marc text)
- marc21_record_type(marc text)
- match_authority_record()
- match_bib_record()
- match_set_test_authxml(record_xml integer, match_set_id text)
- match_set_test_marcxml(bucket_id integer, record_xml text, match_set_id integer)
- measure_auth_record_quality(match_set_id text, xml integer)
- measure_record_quality(match_set_id text, xml integer)
- merge_record_xml(strip_rule text, replace_preserve_rule text, add_rule text, source_xml text, target_xml text)
- merge_record_xml(template_marc text, target_marc text)
- merge_record_xml_using_profile(merge_profile_id text, existing_marc text, incoming_marc bigint)
- overlay_authority_record(merge_profile_id bigint, eg_id bigint, import_id integer)
- overlay_bib_record(merge_profile_id bigint, eg_id bigint, import_id integer)
- replace_field(field text, source_xml text, target_xml text)
- strip_field(field text, xml text)
- template_overlay_bib_record(eg_id text, v_marc bigint)
- template_overlay_bib_record(merge_profile_id text, eg_id bigint, v_marc integer)
Schema acq
Table: acq.acq_lineitem_history
F-Key | Name | Type | Description |
---|---|---|---|
audit_id | bigint | PRIMARY KEY | |
audit_time | timestamp with time zone | NOT NULL | |
audit_action | text | NOT NULL | |
id | bigint | NOT NULL | |
creator | integer | NOT NULL | |
editor | integer | NOT NULL | |
selector | integer | NOT NULL | |
provider | integer | ||
purchase_order | integer | ||
picklist | integer | ||
expected_recv_time | timestamp with time zone | ||
create_time | timestamp with time zone | NOT NULL | |
edit_time | timestamp with time zone | NOT NULL | |
marc | text | NOT NULL | |
eg_bib_id | bigint | ||
source_label | text | ||
state | text | NOT NULL | |
cancel_reason | integer | ||
estimated_unit_price | numeric | ||
claim_policy | integer | ||
queued_record | bigint |
View: acq.acq_lineitem_lifecycle
F-Key | Name | Type | Description |
---|---|---|---|
?column? | bigint | ||
audit_time | timestamp with time zone | ||
audit_action | text | ||
id | bigint | ||
creator | integer | ||
editor | integer | ||
selector | integer | ||
provider | integer | ||
purchase_order | integer | ||
picklist | integer | ||
expected_recv_time | timestamp with time zone | ||
create_time | timestamp with time zone | ||
edit_time | timestamp with time zone | ||
marc | text | ||
eg_bib_id | bigint | ||
source_label | text | ||
state | text | ||
cancel_reason | integer | ||
estimated_unit_price | numeric | ||
claim_policy | integer | ||
queued_record | bigint |
SELECT'-1'::integer AS "?column?" , now () AS audit_time , '-'::text AS audit_action , lineitem.id , lineitem.creator , lineitem.editor , lineitem.selector , lineitem.provider , lineitem.purchase_order , lineitem.picklist , lineitem.expected_recv_time , lineitem.create_time , lineitem.edit_time , lineitem.marc , lineitem.eg_bib_id , lineitem.source_label , lineitem.state , lineitem.cancel_reason , lineitem.estimated_unit_price , lineitem.claim_policy , lineitem.queued_record FROM acq.lineitem UNION ALL SELECT acq_lineitem_history.audit_id AS "?column?" , acq_lineitem_history.audit_time , acq_lineitem_history.audit_action , acq_lineitem_history.id , acq_lineitem_history.creator , acq_lineitem_history.editor , acq_lineitem_history.selector , acq_lineitem_history.provider , acq_lineitem_history.purchase_order , acq_lineitem_history.picklist , acq_lineitem_history.expected_recv_time , acq_lineitem_history.create_time , acq_lineitem_history.edit_time , acq_lineitem_history.marc , acq_lineitem_history.eg_bib_id , acq_lineitem_history.source_label , acq_lineitem_history.state , acq_lineitem_history.cancel_reason , acq_lineitem_history.estimated_unit_price , acq_lineitem_history.claim_policy , acq_lineitem_history.queued_record FROM acq.acq_lineitem_history;
Table: acq.acq_purchase_order_history
F-Key | Name | Type | Description |
---|---|---|---|
audit_id | bigint | PRIMARY KEY | |
audit_time | timestamp with time zone | NOT NULL | |
audit_action | text | NOT NULL | |
id | integer | NOT NULL | |
owner | integer | NOT NULL | |
creator | integer | NOT NULL | |
editor | integer | NOT NULL | |
ordering_agency | integer | NOT NULL | |
create_time | timestamp with time zone | NOT NULL | |
edit_time | timestamp with time zone | NOT NULL | |
provider | integer | NOT NULL | |
state | text | NOT NULL | |
order_date | timestamp with time zone | ||
name | text | NOT NULL | |
cancel_reason | integer | ||
prepayment_required | boolean | NOT NULL |
View: acq.acq_purchase_order_lifecycle
F-Key | Name | Type | Description |
---|---|---|---|
?column? | bigint | ||
audit_time | timestamp with time zone | ||
audit_action | text | ||
id | integer | ||
owner | integer | ||
creator | integer | ||
editor | integer | ||
ordering_agency | integer | ||
create_time | timestamp with time zone | ||
edit_time | timestamp with time zone | ||
provider | integer | ||
state | text | ||
order_date | timestamp with time zone | ||
name | text | ||
cancel_reason | integer | ||
prepayment_required | boolean |
SELECT'-1'::integer AS "?column?" , now () AS audit_time , '-'::text AS audit_action , purchase_order.id , purchase_order.owner , purchase_order.creator , purchase_order.editor , purchase_order.ordering_agency , purchase_order.create_time , purchase_order.edit_time , purchase_order.provider , purchase_order.state , purchase_order.order_date , purchase_order.name , purchase_order.cancel_reason , purchase_order.prepayment_required FROM acq.purchase_order UNION ALL SELECT acq_purchase_order_history.audit_id AS "?column?" , acq_purchase_order_history.audit_time , acq_purchase_order_history.audit_action , acq_purchase_order_history.id , acq_purchase_order_history.owner , acq_purchase_order_history.creator , acq_purchase_order_history.editor , acq_purchase_order_history.ordering_agency , acq_purchase_order_history.create_time , acq_purchase_order_history.edit_time , acq_purchase_order_history.provider , acq_purchase_order_history.state , acq_purchase_order_history.order_date , acq_purchase_order_history.name , acq_purchase_order_history.cancel_reason , acq_purchase_order_history.prepayment_required FROM acq.acq_purchase_order_history;
View: acq.all_fund_allocation_total
F-Key | Name | Type | Description |
---|---|---|---|
fund | integer | ||
amount | numeric |
SELECT f.id AS fund , COALESCE ( (sum ( (a.amount * acq.exchange_ratio (s.currency_type , f.currency_type ) ) ) )::numeric (100 ,2 ) , (0)::numeric ) AS amount FROM ( (acq.fund f LEFT JOIN acq.fund_allocation a ON ( (a.fund = f.id) ) ) LEFT JOIN acq.funding_source s ON ( (a.funding_source = s.id) ) ) GROUP BY f.id;
View: acq.all_fund_combined_balance
F-Key | Name | Type | Description |
---|---|---|---|
fund | integer | ||
amount | numeric |
SELECT a.fund , (a.amount - COALESCE (c.amount , (0)::numeric ) ) AS amount FROM (acq.all_fund_allocation_total a LEFT JOIN ( SELECT fund_debit.fund , sum (fund_debit.amount) AS amount FROM acq.fund_debit GROUP BY fund_debit.fund ) c USING (fund) );
View: acq.all_fund_encumbrance_total
F-Key | Name | Type | Description |
---|---|---|---|
fund | integer | ||
amount | numeric |
SELECT f.id AS fund , COALESCE (encumb.amount , (0)::numeric ) AS amount FROM (acq.fund f LEFT JOIN ( SELECT fund_debit.fund , sum (fund_debit.amount) AS amount FROM acq.fund_debit WHERE fund_debit.encumbrance GROUP BY fund_debit.fund ) encumb ON ( (f.id = encumb.fund) ) );
View: acq.all_fund_spent_balance
F-Key | Name | Type | Description |
---|---|---|---|
fund | integer | ||
amount | numeric |
SELECT c.fund , (c.amount - d.amount) AS amount FROM (acq.all_fund_allocation_total c LEFT JOIN acq.all_fund_spent_total d USING (fund) );
View: acq.all_fund_spent_total
F-Key | Name | Type | Description |
---|---|---|---|
fund | integer | ||
amount | numeric |
SELECT f.id AS fund , COALESCE (spent.amount , (0)::numeric ) AS amount FROM (acq.fund f LEFT JOIN ( SELECT fund_debit.fund , sum (fund_debit.amount) AS amount FROM acq.fund_debit WHERE (NOT fund_debit.encumbrance) GROUP BY fund_debit.fund ) spent ON ( (f.id = spent.fund) ) );
Table: acq.cancel_reason
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | org_unit | integer | UNIQUE#1 NOT NULL |
label | text | UNIQUE#1 NOT NULL | |
description | text | NOT NULL | |
keep_debits | boolean | NOT NULL DEFAULT false |
Tables referencing this one via Foreign Key Constraints:
Table: acq.claim
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
acq.claim_type.id | type | integer | NOT NULL |
acq.lineitem_detail.id | lineitem_detail | bigint | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
claim_lid_idx lineitem_detailTable: acq.claim_event
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
acq.claim_event_type.id | type | integer | NOT NULL |
acq.claim.id | claim | serial | NOT NULL |
event_date | timestamp with time zone | NOT NULL DEFAULT now() | |
actor.usr.id | creator | integer | NOT NULL |
note | text |
Table: acq.claim_event_type
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | org_unit | integer | UNIQUE#1 NOT NULL |
code | text | UNIQUE#1 NOT NULL | |
description | text | NOT NULL | |
library_initiated | boolean | NOT NULL DEFAULT false |
Tables referencing this one via Foreign Key Constraints:
Table: acq.claim_policy
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | org_unit | integer | UNIQUE#1 NOT NULL |
name | text | UNIQUE#1 NOT NULL | |
description | text | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: acq.claim_policy_action
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
acq.claim_policy.id | claim_policy | integer | UNIQUE#1 NOT NULL |
action_interval | interval | UNIQUE#1 NOT NULL | |
acq.claim_event_type.id | action | integer | NOT NULL |
Table: acq.claim_type
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | org_unit | integer | UNIQUE#1 NOT NULL |
code | text | UNIQUE#1 NOT NULL | |
description | text | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: acq.currency_type
F-Key | Name | Type | Description |
---|---|---|---|
code | text | PRIMARY KEY | |
label | text |
Tables referencing this one via Foreign Key Constraints:
Table: acq.debit_attribution
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | PRIMARY KEY | |
acq.fund_debit.id | fund_debit | integer | NOT NULL |
debit_amount | numeric | NOT NULL | |
acq.funding_source_credit.id | funding_source_credit | integer | |
credit_amount | numeric |
Table: acq.distribution_formula
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | owner | integer | UNIQUE#1 NOT NULL |
name | text | UNIQUE#1 NOT NULL | |
skip_count | integer | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: acq.distribution_formula_application
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
actor.usr.id | creator | integer | NOT NULL |
create_time | timestamp with time zone | NOT NULL DEFAULT now() | |
acq.distribution_formula.id | formula | integer | NOT NULL |
acq.lineitem.id | lineitem | integer | NOT NULL |
Table: acq.distribution_formula_entry
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
acq.distribution_formula.id | formula | integer | UNIQUE#1 NOT NULL |
position | integer | UNIQUE#1 NOT NULL | |
item_count | integer | NOT NULL | |
actor.org_unit.id | owning_lib | integer | |
asset.copy_location.id | location | integer | |
acq.fund.id | fund | integer | |
config.circ_modifier.code | circ_modifier | text | |
collection_code | text |
Name | Constraint |
---|---|
acqdfe_must_be_somewhere | CHECK (((owning_lib IS NOT NULL) OR (location IS NOT NULL))) |
Table: acq.edi_account
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | PRIMARY KEY DEFAULT nextval('config.remote_account_id_seq'::regclass) | |
label | text | NOT NULL | |
host | text | NOT NULL | |
username | text | ||
password | text | ||
account | text | ||
path | text | ||
owner | integer | NOT NULL | |
last_activity | timestamp with time zone | ||
acq.provider.id | provider | integer | NOT NULL |
in_dir | text | ||
vendcode | text | ||
vendacct | text | ||
acq.edi_attr_set.id | attr_set | integer | |
use_attrs | boolean | NOT NULL DEFAULT false |
Table acq.edi_account Inherits remote_account,
Tables referencing this one via Foreign Key Constraints:
Table: acq.edi_attr
F-Key | Name | Type | Description |
---|---|---|---|
key | text | PRIMARY KEY | |
label | text | UNIQUE NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: acq.edi_attr_set
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
label | text | UNIQUE NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: acq.edi_attr_set_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
acq.edi_attr_set.id | attr_set | integer | UNIQUE#1 NOT NULL |
acq.edi_attr.key | attr | text | UNIQUE#1 NOT NULL |
Table: acq.edi_message
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
acq.edi_account.id | account | integer | |
remote_file | text | ||
create_time | timestamp with time zone | NOT NULL DEFAULT now() | |
translate_time | timestamp with time zone | ||
process_time | timestamp with time zone | ||
error_time | timestamp with time zone | ||
status | text | NOT NULL DEFAULT 'new'::text | |
edi | text | ||
jedi | text | ||
error | text | ||
acq.purchase_order.id | purchase_order | integer | |
message_type | text | NOT NULL |
Name | Constraint |
---|---|
status_value | CHECK ((status = ANY (ARRAY['new'::text, 'translated'::text, 'trans_error'::text, 'processed'::text, 'proc_error'::text, 'delete_error'::text, 'retry'::text, 'complete'::text]))) |
valid_message_type | CHECK ((message_type = ANY (ARRAY['ORDERS'::text, 'ORDRSP'::text, 'INVOIC'::text, 'OSTENQ'::text, 'OSTRPT'::text, 'DESADV'::text]))) |
Table: acq.exchange_rate
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
acq.currency_type.code | from_currency | text | UNIQUE#1 NOT NULL |
acq.currency_type.code | to_currency | text | UNIQUE#1 NOT NULL |
ratio | numeric | NOT NULL |
Table: acq.fiscal_calendar
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: acq.fiscal_year
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
acq.fiscal_calendar.id | calendar | integer | UNIQUE#1 UNIQUE#2 NOT NULL |
year | integer | UNIQUE#1 NOT NULL | |
year_begin | timestamp with time zone | UNIQUE#2 NOT NULL | |
year_end | timestamp with time zone | NOT NULL |
Table: acq.fund
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | org | integer | UNIQUE#2 UNIQUE#1 NOT NULL |
name | text | UNIQUE#1 NOT NULL | |
year | integer | UNIQUE#2 UNIQUE#1 NOT NULL DEFAULT date_part('year'::text, now()) | |
acq.currency_type.code | currency_type | text | NOT NULL |
code | text | UNIQUE#2 NOT NULL | |
rollover | boolean | NOT NULL DEFAULT false | |
propagate | boolean | NOT NULL DEFAULT true | |
active | boolean | NOT NULL DEFAULT true | |
balance_warning_percent | integer | ||
balance_stop_percent | integer |
Name | Constraint |
---|---|
acq_fund_rollover_implies_propagate | CHECK ((propagate OR (NOT rollover))) |
Tables referencing this one via Foreign Key Constraints:
Table: acq.fund_allocation
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
acq.funding_source.id | funding_source | integer | NOT NULL |
acq.fund.id | fund | integer | NOT NULL |
amount | numeric | NOT NULL | |
actor.usr.id | allocator | integer | NOT NULL |
note | text | ||
create_time | timestamp with time zone | NOT NULL DEFAULT now() |
Table: acq.fund_allocation_percent
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
acq.funding_source.id | funding_source | integer | UNIQUE#1 NOT NULL |
actor.org_unit.id | org | integer | UNIQUE#1 NOT NULL |
fund_code | text | UNIQUE#1 | |
percent | numeric | NOT NULL | |
actor.usr.id | allocator | integer | NOT NULL |
note | text | ||
create_time | timestamp with time zone | NOT NULL DEFAULT now() |
Name | Constraint |
---|---|
percentage_range | CHECK (((percent >= (0)::numeric) AND (percent <= (100)::numeric))) |
View: acq.fund_allocation_total
F-Key | Name | Type | Description |
---|---|---|---|
fund | integer | ||
amount | numeric(100,2) |
SELECT a.fund , (sum ( (a.amount * acq.exchange_ratio (s.currency_type , f.currency_type ) ) ) )::numeric (100 ,2 ) AS amount FROM ( (acq.fund_allocation a JOIN acq.fund f ON ( (a.fund = f.id) ) ) JOIN acq.funding_source s ON ( (a.funding_source = s.id) ) ) GROUP BY a.fund;
View: acq.fund_combined_balance
F-Key | Name | Type | Description |
---|---|---|---|
fund | integer | ||
amount | numeric |
SELECT c.fund , (c.amount - COALESCE (d.amount , 0.0 ) ) AS amount FROM (acq.fund_allocation_total c LEFT JOIN acq.fund_debit_total d USING (fund) );
Table: acq.fund_debit
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
acq.fund.id | fund | integer | NOT NULL |
origin_amount | numeric | NOT NULL | |
acq.currency_type.code | origin_currency_type | text | NOT NULL |
amount | numeric | NOT NULL | |
encumbrance | boolean | NOT NULL DEFAULT true | |
debit_type | text | NOT NULL | |
acq.fund.id | xfer_destination | integer | |
create_time | timestamp with time zone | NOT NULL DEFAULT now() | |
acq.invoice_entry.id | invoice_entry | integer |
Tables referencing this one via Foreign Key Constraints:
fund_debit_invoice_entry_idx invoice_entryView: acq.fund_debit_total
F-Key | Name | Type | Description |
---|---|---|---|
fund | integer | ||
amount | numeric |
SELECT fund.id AS fund , sum (COALESCE (fund_debit.amount , (0)::numeric ) ) AS amount FROM (acq.fund fund LEFT JOIN acq.fund_debit fund_debit ON ( (fund.id = fund_debit.fund) ) ) GROUP BY fund.id;
View: acq.fund_encumbrance_total
F-Key | Name | Type | Description |
---|---|---|---|
fund | integer | ||
amount | numeric |
SELECT fund.id AS fund , sum (COALESCE (fund_debit.amount , (0)::numeric ) ) AS amount FROM (acq.fund fund LEFT JOIN acq.fund_debit fund_debit ON ( (fund.id = fund_debit.fund) ) ) WHERE fund_debit.encumbrance GROUP BY fund.id;
View: acq.fund_spent_balance
F-Key | Name | Type | Description |
---|---|---|---|
fund | integer | ||
amount | numeric |
SELECT c.fund , (c.amount - COALESCE (d.amount , 0.0 ) ) AS amount FROM (acq.fund_allocation_total c LEFT JOIN acq.fund_spent_total d USING (fund) );
View: acq.fund_spent_total
F-Key | Name | Type | Description |
---|---|---|---|
fund | integer | ||
amount | numeric |
SELECT fund.id AS fund , sum (COALESCE (fund_debit.amount , (0)::numeric ) ) AS amount FROM (acq.fund fund LEFT JOIN acq.fund_debit fund_debit ON ( (fund.id = fund_debit.fund) ) ) WHERE (NOT fund_debit.encumbrance) GROUP BY fund.id;
Table: acq.fund_tag
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | owner | integer | UNIQUE#1 NOT NULL |
name | text | UNIQUE#1 NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: acq.fund_tag_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
acq.fund.id | fund | integer | UNIQUE#1 NOT NULL |
acq.fund_tag.id | tag | integer | UNIQUE#1 |
Table: acq.fund_transfer
Fund Transfer Each row represents the transfer of money from a source fund to a destination fund. There should be corresponding entries in acq.fund_allocation. The purpose of acq.fund_transfer is to record how much money moved from which fund to which other fund. The presence of two amount fields, rather than one, reflects the possibility that the two funds are denominated in different currencies. If they use the same currency type, the two amounts should be the same.
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
acq.fund.id | src_fund | integer | NOT NULL |
src_amount | numeric | NOT NULL | |
acq.fund.id | dest_fund | integer | |
dest_amount | numeric | ||
transfer_time | timestamp with time zone | NOT NULL DEFAULT now() | |
actor.usr.id | transfer_user | integer | NOT NULL |
note | text | ||
acq.funding_source_credit.id | funding_source_credit | integer | NOT NULL |
Table: acq.funding_source
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE#2 NOT NULL | |
actor.org_unit.id | owner | integer | UNIQUE#1 UNIQUE#2 NOT NULL |
acq.currency_type.code | currency_type | text | NOT NULL |
code | text | UNIQUE#1 NOT NULL | |
active | boolean | NOT NULL DEFAULT true |
Tables referencing this one via Foreign Key Constraints:
View: acq.funding_source_allocation_total
F-Key | Name | Type | Description |
---|---|---|---|
funding_source | integer | ||
amount | numeric(100,2) |
SELECT a.funding_source , (sum (a.amount) )::numeric (100 ,2 ) AS amount FROM acq.fund_allocation a GROUP BY a.funding_source;
View: acq.funding_source_balance
F-Key | Name | Type | Description |
---|---|---|---|
funding_source | integer | ||
amount | numeric(100,2) |
SELECT COALESCE (c.funding_source , a.funding_source ) AS funding_source , (sum ( (COALESCE (c.amount , 0.0 ) - COALESCE (a.amount , 0.0 ) ) ) )::numeric (100 ,2 ) AS amount FROM (acq.funding_source_credit_total c FULL JOIN acq.funding_source_allocation_total a USING (funding_source) ) GROUP BY COALESCE (c.funding_source , a.funding_source );
Table: acq.funding_source_credit
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
acq.funding_source.id | funding_source | integer | NOT NULL |
amount | numeric | NOT NULL | |
note | text | ||
deadline_date | timestamp with time zone | ||
effective_date | timestamp with time zone | NOT NULL DEFAULT now() |
Tables referencing this one via Foreign Key Constraints:
View: acq.funding_source_credit_total
F-Key | Name | Type | Description |
---|---|---|---|
funding_source | integer | ||
amount | numeric |
SELECT funding_source_credit.funding_source , sum (funding_source_credit.amount) AS amount FROM acq.funding_source_credit GROUP BY funding_source_credit.funding_source;
Table: acq.invoice
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | receiver | integer | NOT NULL |
acq.provider.id | provider | integer | UNIQUE#1 NOT NULL |
acq.provider.id | shipper | integer | NOT NULL |
recv_date | timestamp with time zone | NOT NULL DEFAULT now() | |
acq.invoice_method.code | recv_method | text | NOT NULL DEFAULT 'EDI'::text |
inv_type | text | ||
inv_ident | text | UNIQUE#1 NOT NULL | |
payment_auth | text | ||
acq.invoice_payment_method.code | payment_method | text | |
note | text | ||
close_date | timestamp with time zone | ||
actor.usr.id | closed_by | integer |
Tables referencing this one via Foreign Key Constraints:
Table: acq.invoice_entry
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
acq.invoice.id | invoice | integer | NOT NULL |
acq.purchase_order.id | purchase_order | integer | |
acq.lineitem.id | lineitem | integer | |
inv_item_count | integer | NOT NULL | |
phys_item_count | integer | ||
note | text | ||
billed_per_item | boolean | ||
cost_billed | numeric(8,2) | ||
actual_cost | numeric(8,2) | ||
amount_paid | numeric(8,2) |
Tables referencing this one via Foreign Key Constraints:
ie_inv_idx invoice ie_li_idx lineitem ie_po_idx purchase_orderTable: acq.invoice_item
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
acq.invoice.id | invoice | integer | NOT NULL |
acq.purchase_order.id | purchase_order | integer | |
acq.fund_debit.id | fund_debit | integer | |
acq.invoice_item_type.code | inv_item_type | text | NOT NULL |
title | text | ||
author | text | ||
note | text | ||
cost_billed | numeric(8,2) | ||
actual_cost | numeric(8,2) | ||
acq.fund.id | fund | integer | |
amount_paid | numeric(8,2) | ||
acq.po_item.id | po_item | integer | |
target | bigint |
Table: acq.invoice_item_type
F-Key | Name | Type | Description |
---|---|---|---|
code | text | PRIMARY KEY | |
name | text | NOT NULL | |
prorate | boolean | NOT NULL DEFAULT false | |
blanket | boolean | NOT NULL DEFAULT false |
Name | Constraint |
---|---|
aiit_not_blanket_and_prorate | CHECK (((blanket IS FALSE) OR (prorate IS FALSE))) |
Tables referencing this one via Foreign Key Constraints:
Table: acq.invoice_method
F-Key | Name | Type | Description |
---|---|---|---|
code | text | PRIMARY KEY | |
name | text | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: acq.invoice_payment_method
F-Key | Name | Type | Description |
---|---|---|---|
code | text | PRIMARY KEY | |
name | text | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
View: acq.li_state_label
F-Key | Name | Type | Description |
---|---|---|---|
id | text | ||
label | text |
SELECT t.id , t.label FROM ( VALUES ('new'::text ,oils_i18n_gettext ('new'::text ,'New'::text ,'jubstlbl'::text ,'label'::text ) ) , ('selector-ready'::text ,oils_i18n_gettext ('selector-ready'::text ,'Selector-Ready'::text ,'jubstlbl'::text ,'label'::text ) ) , ('order-ready'::text ,oils_i18n_gettext ('order-ready'::text ,'Order-Ready'::text ,'jubstlbl'::text ,'label'::text ) ) , ('approved'::text ,oils_i18n_gettext ('approved'::text ,'Approved'::text ,'jubstlbl'::text ,'label'::text ) ) , ('pending-order'::text ,oils_i18n_gettext ('pending-order'::text ,'Pending-Order'::text ,'jubstlbl'::text ,'label'::text ) ) , ('on-order'::text ,oils_i18n_gettext ('on-order'::text ,'On-Order'::text ,'jubstlbl'::text ,'label'::text ) ) , ('received'::text ,oils_i18n_gettext ('received'::text ,'Received'::text ,'jubstlbl'::text ,'label'::text ) ) , ('cancelled'::text ,oils_i18n_gettext ('cancelled'::text ,'Cancelled'::text ,'jubstlbl'::text ,'label'::text ) ) ) t (id , label );
Table: acq.lineitem
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
actor.usr.id | creator | integer | NOT NULL |
actor.usr.id | editor | integer | NOT NULL |
actor.usr.id | selector | integer | NOT NULL |
acq.provider.id | provider | integer | |
acq.purchase_order.id | purchase_order | integer | |
acq.picklist.id | picklist | integer | |
expected_recv_time | timestamp with time zone | ||
create_time | timestamp with time zone | NOT NULL DEFAULT now() | |
edit_time | timestamp with time zone | NOT NULL DEFAULT now() | |
marc | text | NOT NULL | |
biblio.record_entry.id | eg_bib_id | bigint | |
source_label | text | ||
state | text | NOT NULL DEFAULT 'new'::text | |
acq.cancel_reason.id | cancel_reason | integer | |
estimated_unit_price | numeric | ||
acq.claim_policy.id | claim_policy | integer | |
vandelay.queued_bib_record.id | queued_record | bigint |
Name | Constraint |
---|---|
picklist_or_po | CHECK (((picklist IS NOT NULL) OR (purchase_order IS NOT NULL))) |
Tables referencing this one via Foreign Key Constraints:
li_creator_idx creator li_editor_idx editor li_pl_idx picklist li_po_idx purchase_order li_queued_record_idx queued_record li_selector_idx selectorTable: acq.lineitem_alert_text
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
code | text | UNIQUE#1 NOT NULL | |
description | text | ||
actor.org_unit.id | owning_lib | integer | UNIQUE#1 NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: acq.lineitem_attr
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
definition | bigint | NOT NULL | |
acq.lineitem.id | lineitem | bigint | NOT NULL |
attr_type | text | NOT NULL | |
attr_name | text | NOT NULL | |
attr_value | text | NOT NULL | |
order_ident | boolean | NOT NULL DEFAULT false |
Table: acq.lineitem_attr_definition
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
code | text | NOT NULL | |
description | text | NOT NULL | |
remove | text | NOT NULL DEFAULT ''::text | |
ident | boolean | NOT NULL DEFAULT false |
Table: acq.lineitem_detail
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
acq.lineitem.id | lineitem | integer | NOT NULL |
acq.fund.id | fund | integer | |
acq.fund_debit.id | fund_debit | integer | |
eg_copy_id | bigint | ||
barcode | text | ||
cn_label | text | ||
note | text | ||
collection_code | text | ||
config.circ_modifier.code | circ_modifier | text | |
actor.org_unit.id | owning_lib | integer | |
asset.copy_location.id | location | integer | |
recv_time | timestamp with time zone | ||
actor.usr.id | receiver | integer | |
acq.cancel_reason.id | cancel_reason | integer |
Tables referencing this one via Foreign Key Constraints:
li_detail_li_idx lineitem lineitem_detail_fund_debit_idx fund_debitTable: acq.lineitem_generated_attr_definition
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY DEFAULT nextval('acq.lineitem_attr_definition_id_seq'::regclass) | |
code | text | NOT NULL | |
description | text | NOT NULL | |
remove | text | NOT NULL DEFAULT ''::text | |
ident | boolean | NOT NULL DEFAULT false | |
xpath | text | NOT NULL |
Table acq.lineitem_generated_attr_definition Inherits lineitem_attr_definition,
Table: acq.lineitem_local_attr_definition
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY DEFAULT nextval('acq.lineitem_attr_definition_id_seq'::regclass) | |
code | text | NOT NULL | |
description | text | NOT NULL | |
remove | text | NOT NULL DEFAULT ''::text | |
ident | boolean | NOT NULL DEFAULT false |
Table acq.lineitem_local_attr_definition Inherits lineitem_attr_definition,
Table: acq.lineitem_marc_attr_definition
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY DEFAULT nextval('acq.lineitem_attr_definition_id_seq'::regclass) | |
code | text | NOT NULL | |
description | text | NOT NULL | |
remove | text | NOT NULL DEFAULT ''::text | |
ident | boolean | NOT NULL DEFAULT false | |
xpath | text | NOT NULL |
Table acq.lineitem_marc_attr_definition Inherits lineitem_attr_definition,
Table: acq.lineitem_note
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
acq.lineitem.id | lineitem | integer | NOT NULL |
actor.usr.id | creator | integer | NOT NULL |
actor.usr.id | editor | integer | NOT NULL |
create_time | timestamp with time zone | NOT NULL DEFAULT now() | |
edit_time | timestamp with time zone | NOT NULL DEFAULT now() | |
value | text | NOT NULL | |
acq.lineitem_alert_text.id | alert_text | integer | |
vendor_public | boolean | NOT NULL DEFAULT false |
Table: acq.lineitem_provider_attr_definition
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY DEFAULT nextval('acq.lineitem_attr_definition_id_seq'::regclass) | |
code | text | NOT NULL | |
description | text | NOT NULL | |
remove | text | NOT NULL DEFAULT ''::text | |
ident | boolean | NOT NULL DEFAULT false | |
xpath | text | NOT NULL | |
acq.provider.id | provider | integer | NOT NULL |
Table acq.lineitem_provider_attr_definition Inherits lineitem_attr_definition,
View: acq.lineitem_summary
F-Key | Name | Type | Description |
---|---|---|---|
lineitem | bigint | ||
item_count | bigint | ||
recv_count | bigint | ||
cancel_count | bigint | ||
delay_count | bigint | ||
invoice_count | bigint | ||
claim_count | bigint | ||
estimated_amount | numeric(8,2) | ||
encumbrance_amount | numeric(8,2) | ||
paid_amount | numeric(8,2) |
SELECT li.id AS lineitem , ( SELECT count (lid.id) AS count FROM acq.lineitem_detail lid WHERE (lid.lineitem = li.id) ) AS item_count , ( SELECT count (lid.id) AS count FROM acq.lineitem_detail lid WHERE ( (lid.recv_time IS NOT NULL) AND (lid.lineitem = li.id) ) ) AS recv_count , ( SELECT count (lid.id) AS count FROM (acq.lineitem_detail lid JOIN acq.cancel_reason acqcr ON ( (acqcr.id = lid.cancel_reason) ) ) WHERE ( (acqcr.keep_debits IS FALSE) AND (lid.lineitem = li.id) ) ) AS cancel_count , ( SELECT count (lid.id) AS count FROM (acq.lineitem_detail lid JOIN acq.cancel_reason acqcr ON ( (acqcr.id = lid.cancel_reason) ) ) WHERE ( (acqcr.keep_debits IS TRUE) AND (lid.lineitem = li.id) ) ) AS delay_count , ( SELECT count (lid.id) AS count FROM (acq.lineitem_detail lid JOIN acq.fund_debit debit ON ( (lid.fund_debit = debit.id) ) ) WHERE ( (NOT debit.encumbrance) AND (lid.lineitem = li.id) ) ) AS invoice_count , ( SELECT count (DISTINCT lid.id) AS count FROM (acq.lineitem_detail lid JOIN acq.claim claim ON ( (claim.lineitem_detail = lid.id) ) ) WHERE (lid.lineitem = li.id) ) AS claim_count , ( SELECT ( ( (count (lid.id) )::numeric * li.estimated_unit_price ) )::numeric (8 ,2 ) AS "numeric" FROM acq.lineitem_detail lid WHERE ( (lid.cancel_reason IS NULL) AND (lid.lineitem = li.id) ) ) AS estimated_amount , ( SELECT (sum (debit.amount) )::numeric (8 ,2 ) AS sum FROM (acq.lineitem_detail lid JOIN acq.fund_debit debit ON ( (lid.fund_debit = debit.id) ) ) WHERE (debit.encumbrance AND (lid.lineitem = li.id) ) ) AS encumbrance_amount , ( SELECT (sum (debit.amount) )::numeric (8 ,2 ) AS sum FROM (acq.lineitem_detail lid JOIN acq.fund_debit debit ON ( (lid.fund_debit = debit.id) ) ) WHERE ( (NOT debit.encumbrance) AND (lid.lineitem = li.id) ) ) AS paid_amount FROM acq.lineitem li;
Table: acq.lineitem_usr_attr_definition
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY DEFAULT nextval('acq.lineitem_attr_definition_id_seq'::regclass) | |
code | text | NOT NULL | |
description | text | NOT NULL | |
remove | text | NOT NULL DEFAULT ''::text | |
ident | boolean | NOT NULL DEFAULT false | |
actor.usr.id | usr | integer | NOT NULL |
Table acq.lineitem_usr_attr_definition Inherits lineitem_attr_definition,
li_usr_attr_def_usr_idx usrView: acq.ordered_funding_source_credit
The acq.ordered_funding_source_credit view is a prioritized ordering of funding source credits. When ordered by the first three columns, this view defines the order in which the various credits are to be tapped for spending, subject to the allocations in the acq.fund_allocation table. The first column reflects the principle that we should spend money with deadlines before spending money without deadlines. The second column reflects the principle that we should spend the oldest money first. For money with deadlines, that means that we spend first from the credit with the earliest deadline. For money without deadlines, we spend first from the credit with the earliest effective date. The third column is a tie breaker to ensure a consistent ordering.
F-Key | Name | Type | Description |
---|---|---|---|
sort_priority | integer | ||
sort_date | timestamp with time zone | ||
id | integer | ||
funding_source | integer | ||
amount | numeric | ||
note | text |
SELECT CASE WHEN (funding_source_credit.deadline_date IS NULL) THEN 2 ELSE 1 END AS sort_priority , CASE WHEN (funding_source_credit.deadline_date IS NULL) THEN funding_source_credit.effective_date ELSE funding_source_credit.deadline_date END AS sort_date , funding_source_credit.id , funding_source_credit.funding_source , funding_source_credit.amount , funding_source_credit.note FROM acq.funding_source_credit;
Table: acq.picklist
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.usr.id | owner | integer | UNIQUE#1 NOT NULL |
actor.usr.id | creator | integer | NOT NULL |
actor.usr.id | editor | integer | NOT NULL |
actor.org_unit.id | org_unit | integer | NOT NULL |
name | text | UNIQUE#1 NOT NULL | |
create_time | timestamp with time zone | NOT NULL DEFAULT now() | |
edit_time | timestamp with time zone | NOT NULL DEFAULT now() |
Tables referencing this one via Foreign Key Constraints:
acq_picklist_creator_idx creator acq_picklist_editor_idx editor acq_picklist_owner_idx ownerTable: acq.po_item
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
acq.purchase_order.id | purchase_order | integer | |
acq.fund_debit.id | fund_debit | integer | |
acq.invoice_item_type.code | inv_item_type | text | NOT NULL |
title | text | ||
author | text | ||
note | text | ||
estimated_cost | numeric(8,2) | ||
acq.fund.id | fund | integer | |
target | bigint |
Tables referencing this one via Foreign Key Constraints:
poi_fund_debit_idx fund_debit poi_po_idx purchase_orderTable: acq.po_note
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
acq.purchase_order.id | purchase_order | integer | NOT NULL |
actor.usr.id | creator | integer | NOT NULL |
actor.usr.id | editor | integer | NOT NULL |
create_time | timestamp with time zone | NOT NULL DEFAULT now() | |
edit_time | timestamp with time zone | NOT NULL DEFAULT now() | |
value | text | NOT NULL | |
vendor_public | boolean | NOT NULL DEFAULT false |
View: acq.po_state_label
F-Key | Name | Type | Description |
---|---|---|---|
id | text | ||
label | text |
SELECT t.id , t.label FROM ( VALUES ('new'::text ,oils_i18n_gettext ('new'::text ,'New'::text ,'acqpostlbl'::text ,'label'::text ) ) , ('pending'::text ,oils_i18n_gettext ('pending'::text ,'Pending'::text ,'acqpostlbl'::text ,'label'::text ) ) , ('on-order'::text ,oils_i18n_gettext ('on-order'::text ,'On-Order'::text ,'acqpostlbl'::text ,'label'::text ) ) , ('received'::text ,oils_i18n_gettext ('received'::text ,'Received'::text ,'acqpostlbl'::text ,'label'::text ) ) , ('cancelled'::text ,oils_i18n_gettext ('cancelled'::text ,'Cancelled'::text ,'acqpostlbl'::text ,'label'::text ) ) ) t (id , label );
Table: acq.provider
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE#1 NOT NULL | |
actor.org_unit.id | owner | integer | UNIQUE#2 UNIQUE#1 NOT NULL |
acq.currency_type.code | currency_type | text | NOT NULL |
code | text | UNIQUE#2 NOT NULL | |
holding_tag | text | ||
san | text | ||
acq.edi_account.id | edi_default | integer | |
active | boolean | NOT NULL DEFAULT true | |
prepayment_required | boolean | NOT NULL DEFAULT false | |
url | text | ||
text | |||
phone | text | ||
fax_phone | text | ||
default_copy_count | integer | NOT NULL | |
acq.claim_policy.id | default_claim_policy | integer | |
acq.provider_contact.id | primary_contact | integer |
Tables referencing this one via Foreign Key Constraints:
Table: acq.provider_address
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
valid | boolean | NOT NULL DEFAULT true | |
address_type | text | ||
acq.provider.id | provider | integer | NOT NULL |
street1 | text | NOT NULL | |
street2 | text | ||
city | text | NOT NULL | |
county | text | ||
state | text | NOT NULL | |
country | text | NOT NULL | |
post_code | text | NOT NULL | |
fax_phone | text |
Table: acq.provider_contact
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
acq.provider.id | provider | integer | NOT NULL |
name | text | NOT NULL | |
role | text | ||
text | |||
phone | text |
Tables referencing this one via Foreign Key Constraints:
Table: acq.provider_contact_address
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
valid | boolean | NOT NULL DEFAULT true | |
address_type | text | ||
acq.provider_contact.id | contact | integer | NOT NULL |
street1 | text | NOT NULL | |
street2 | text | ||
city | text | NOT NULL | |
county | text | ||
state | text | NOT NULL | |
country | text | NOT NULL | |
post_code | text | NOT NULL | |
fax_phone | text |
Table: acq.provider_holding_subfield_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
acq.provider.id | provider | integer | UNIQUE#1 NOT NULL |
name | text | UNIQUE#1 NOT NULL | |
subfield | text | NOT NULL |
Table: acq.provider_note
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
acq.provider.id | provider | integer | NOT NULL |
actor.usr.id | creator | integer | NOT NULL |
actor.usr.id | editor | integer | NOT NULL |
create_time | timestamp with time zone | NOT NULL DEFAULT now() | |
edit_time | timestamp with time zone | NOT NULL DEFAULT now() | |
value | text | NOT NULL |
Table: acq.purchase_order
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.usr.id | owner | integer | NOT NULL |
actor.usr.id | creator | integer | NOT NULL |
actor.usr.id | editor | integer | NOT NULL |
actor.org_unit.id | ordering_agency | integer | NOT NULL |
create_time | timestamp with time zone | NOT NULL DEFAULT now() | |
edit_time | timestamp with time zone | NOT NULL DEFAULT now() | |
acq.provider.id | provider | integer | NOT NULL |
state | text | NOT NULL DEFAULT 'new'::text | |
order_date | timestamp with time zone | ||
name | text | NOT NULL | |
acq.cancel_reason.id | cancel_reason | integer | |
prepayment_required | boolean | NOT NULL DEFAULT false |
Name | Constraint |
---|---|
valid_po_state | CHECK ((state = ANY (ARRAY['new'::text, 'pending'::text, 'on-order'::text, 'received'::text, 'cancelled'::text]))) |
Tables referencing this one via Foreign Key Constraints:
acq_po_org_name_order_date_idx ordering_agency, name, order_date po_creator_idx creator po_editor_idx editor po_owner_idx owner po_provider_idx provider po_state_idx stateTable: acq.serial_claim
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
acq.claim_type.id | type | integer | NOT NULL |
serial.item.id | item | bigint | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
serial_claim_lid_idx itemTable: acq.serial_claim_event
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
acq.claim_event_type.id | type | integer | NOT NULL |
acq.serial_claim.id | claim | serial | NOT NULL |
event_date | timestamp with time zone | NOT NULL DEFAULT now() | |
actor.usr.id | creator | integer | NOT NULL |
note | text |
Table: acq.shipment_notification
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | receiver | integer | NOT NULL |
acq.provider.id | provider | integer | UNIQUE#1 NOT NULL |
acq.provider.id | shipper | integer | NOT NULL |
recv_date | timestamp with time zone | NOT NULL DEFAULT now() | |
acq.invoice_method.code | recv_method | text | NOT NULL DEFAULT 'EDI'::text |
process_date | timestamp with time zone | ||
actor.usr.id | processed_by | integer | |
container_code | text | UNIQUE#1 NOT NULL | |
lading_number | text | ||
note | text |
Tables referencing this one via Foreign Key Constraints:
acq_asn_container_code_idx container_codeTable: acq.shipment_notification_entry
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
acq.shipment_notification.id | shipment_notification | integer | NOT NULL |
acq.lineitem.id | lineitem | integer | |
item_count | integer | NOT NULL |
Table: acq.user_request
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.usr.id | usr | integer | NOT NULL |
hold | boolean | NOT NULL DEFAULT true | |
actor.org_unit.id | pickup_lib | integer | NOT NULL |
holdable_formats | text | ||
phone_notify | text | ||
email_notify | boolean | NOT NULL DEFAULT true | |
acq.lineitem.id | lineitem | integer | |
biblio.record_entry.id | eg_bib | bigint | |
request_date | timestamp with time zone | NOT NULL DEFAULT now() | |
need_before | timestamp with time zone | ||
max_fee | text | ||
acq.user_request_type.id | request_type | integer | NOT NULL |
isxn | text | ||
upc | text | ||
title | text | ||
volume | text | ||
author | text | ||
article_title | text | ||
article_pages | text | ||
publisher | text | ||
location | text | ||
pubdate | text | ||
mentioned | text | ||
other_info | text | ||
acq.cancel_reason.id | cancel_reason | integer | |
cancel_time | timestamp with time zone |
Tables referencing this one via Foreign Key Constraints:
Table: acq.user_request_status_type
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
label | text |
Table: acq.user_request_type
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
label | text | UNIQUE NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Function: acq.attribute_debits()
Returns: void
Language: PLPGSQL
/* Function to attribute expenditures and encumbrances to funding source credits, and thereby to funding sources. Read the debits in chonological order, attributing each one to one or more funding source credits. Constraints: 1. Don't attribute more to a credit than the amount of the credit. 2. For a given fund, don't attribute more to a funding source than the source has allocated to that fund. 3. Attribute debits to credits with deadlines before attributing them to credits without deadlines. Otherwise attribute to the earliest credits first, based on the deadline date when present, or on the effective date when there is no deadline. Use funding_source_credit.id as a tie-breaker. This ordering is defined by an ORDER BY clause on the view acq.ordered_funding_source_credit. Start by truncating the table acq.debit_attribution. Then insert a row into that table for each attribution. If a debit cannot be fully attributed, insert a row for the unattributable balance, with the funding_source_credit and credit_amount columns NULL. */ DECLARE curr_fund_source_bal RECORD; seqno INT; -- sequence num for credits applicable to a fund fund_credit RECORD; -- current row in temp t_fund_credit table fc RECORD; -- used for loading t_fund_credit table sc RECORD; -- used for loading t_fund_credit table -- -- Used exclusively in the main loop: -- deb RECORD; -- current row from acq.fund_debit table curr_credit_bal RECORD; -- current row from temp t_credit table debit_balance NUMERIC; -- amount left to attribute for current debit conv_debit_balance NUMERIC; -- debit balance in currency of the fund attr_amount NUMERIC; -- amount being attributed, in currency of debit conv_attr_amount NUMERIC; -- amount being attributed, in currency of source conv_cred_balance NUMERIC; -- credit_balance in the currency of the fund conv_alloc_balance NUMERIC; -- allocated balance in the currency of the fund attrib_count INT; -- populates id of acq.debit_attribution BEGIN -- -- Load a temporary table. For each combination of fund and funding source, -- load an entry with the total amount allocated to that fund by that source. -- This sum may reflect transfers as well as original allocations. We will -- reduce this balance whenever we attribute debits to it. -- CREATE TEMP TABLE t_fund_source_bal ON COMMIT DROP AS SELECT fund AS fund, funding_source AS source, sum( amount ) AS balance FROM acq.fund_allocation GROUP BY fund, funding_source HAVING sum( amount ) > 0; -- CREATE INDEX t_fund_source_bal_idx ON t_fund_source_bal( fund, source ); ------------------------------------------------------------------------------- -- -- Load another temporary table. For each fund, load zero or more -- funding source credits from which that fund can get money. -- CREATE TEMP TABLE t_fund_credit ( fund INT, seq INT, credit INT ) ON COMMIT DROP; -- FOR fc IN SELECT DISTINCT fund FROM acq.fund_allocation ORDER BY fund LOOP -- Loop over the funds seqno := 1; FOR sc IN SELECT ofsc.id FROM acq.ordered_funding_source_credit AS ofsc WHERE ofsc.funding_source IN ( SELECT funding_source FROM acq.fund_allocation WHERE fund = fc.fund ) ORDER BY ofsc.sort_priority, ofsc.sort_date, ofsc.id LOOP -- Add each credit to the list INSERT INTO t_fund_credit ( fund, seq, credit ) VALUES ( fc.fund, seqno, sc.id ); --RAISE NOTICE 'Fund % credit %', fc.fund, sc.id; seqno := seqno + 1; END LOOP; -- Loop over credits for a given fund END LOOP; -- Loop over funds -- CREATE INDEX t_fund_credit_idx ON t_fund_credit( fund, seq ); ------------------------------------------------------------------------------- -- -- Load yet another temporary table. This one is a list of funding source -- credits, with their balances. We shall reduce those balances as we -- attribute debits to them. -- CREATE TEMP TABLE t_credit ON COMMIT DROP AS SELECT fsc.id AS credit, fsc.funding_source AS source, fsc.amount AS balance, fs.currency_type AS currency_type FROM acq.funding_source_credit AS fsc, acq.funding_source fs WHERE fsc.funding_source = fs.id AND fsc.amount > 0; -- CREATE INDEX t_credit_idx ON t_credit( credit ); -- ------------------------------------------------------------------------------- -- -- Now that we have loaded the lookup tables: loop through the debits, -- attributing each one to one or more funding source credits. -- truncate table acq.debit_attribution; -- attrib_count := 0; FOR deb in SELECT fd.id, fd.fund, fd.amount, f.currency_type, fd.encumbrance FROM acq.fund_debit fd, acq.fund f WHERE fd.fund = f.id ORDER BY fd.id LOOP --RAISE NOTICE 'Debit %, fund %', deb.id, deb.fund; -- debit_balance := deb.amount; -- -- Loop over the funding source credits that are eligible -- to pay for this debit -- FOR fund_credit IN SELECT credit FROM t_fund_credit WHERE fund = deb.fund ORDER BY seq LOOP --RAISE NOTICE ' Examining credit %', fund_credit.credit; -- -- Look up the balance for this credit. If it's zero, then -- it's not useful, so treat it as if you didn't find it. -- (Actually there shouldn't be any zero balances in the table, -- but we check just to make sure.) -- SELECT * INTO curr_credit_bal FROM t_credit WHERE credit = fund_credit.credit AND balance > 0; -- IF curr_credit_bal IS NULL THEN -- -- This credit is exhausted; try the next one. -- CONTINUE; END IF; -- -- -- At this point we have an applicable credit with some money left. -- Now see if the relevant funding_source has any money left. -- -- Look up the balance of the allocation for this combination of -- fund and source. If you find such an entry, but it has a zero -- balance, then it's not useful, so treat it as unfound. -- (Actually there shouldn't be any zero balances in the table, -- but we check just to make sure.) -- SELECT * INTO curr_fund_source_bal FROM t_fund_source_bal WHERE fund = deb.fund AND source = curr_credit_bal.source AND balance > 0; -- IF curr_fund_source_bal IS NULL THEN -- -- This fund/source doesn't exist or is already exhausted, -- so we can't use this credit. Go on to the next one. -- CONTINUE; END IF; -- -- Convert the available balances to the currency of the fund -- conv_alloc_balance := curr_fund_source_bal.balance * acq.exchange_ratio( curr_credit_bal.currency_type, deb.currency_type ); conv_cred_balance := curr_credit_bal.balance * acq.exchange_ratio( curr_credit_bal.currency_type, deb.currency_type ); -- -- Determine how much we can attribute to this credit: the minimum -- of the debit amount, the fund/source balance, and the -- credit balance -- --RAISE NOTICE ' deb bal %', debit_balance; --RAISE NOTICE ' source % balance %', curr_credit_bal.source, conv_alloc_balance; --RAISE NOTICE ' credit % balance %', curr_credit_bal.credit, conv_cred_balance; -- conv_attr_amount := NULL; attr_amount := debit_balance; -- IF attr_amount > conv_alloc_balance THEN attr_amount := conv_alloc_balance; conv_attr_amount := curr_fund_source_bal.balance; END IF; IF attr_amount > conv_cred_balance THEN attr_amount := conv_cred_balance; conv_attr_amount := curr_credit_bal.balance; END IF; -- -- If we're attributing all of one of the balances, then that's how -- much we will deduct from the balances, and we already captured -- that amount above. Otherwise we must convert the amount of the -- attribution from the currency of the fund back to the currency of -- the funding source. -- IF conv_attr_amount IS NULL THEN conv_attr_amount := attr_amount * acq.exchange_ratio( deb.currency_type, curr_credit_bal.currency_type ); END IF; -- -- Insert a row to record the attribution -- attrib_count := attrib_count + 1; INSERT INTO acq.debit_attribution ( id, fund_debit, debit_amount, funding_source_credit, credit_amount ) VALUES ( attrib_count, deb.id, attr_amount, curr_credit_bal.credit, conv_attr_amount ); -- -- Subtract the attributed amount from the various balances -- debit_balance := debit_balance - attr_amount; curr_fund_source_bal.balance := curr_fund_source_bal.balance - conv_attr_amount; -- IF curr_fund_source_bal.balance <= 0 THEN -- -- This allocation is exhausted. Delete it so -- that we don't waste time looking at it again. -- DELETE FROM t_fund_source_bal WHERE fund = curr_fund_source_bal.fund AND source = curr_fund_source_bal.source; ELSE UPDATE t_fund_source_bal SET balance = balance - conv_attr_amount WHERE fund = curr_fund_source_bal.fund AND source = curr_fund_source_bal.source; END IF; -- IF curr_credit_bal.balance <= 0 THEN -- -- This funding source credit is exhausted. Delete it -- so that we don't waste time looking at it again. -- --DELETE FROM t_credit --WHERE -- credit = curr_credit_bal.credit; -- DELETE FROM t_fund_credit WHERE credit = curr_credit_bal.credit; ELSE UPDATE t_credit SET balance = curr_credit_bal.balance WHERE credit = curr_credit_bal.credit; END IF; -- -- Are we done with this debit yet? -- IF debit_balance <= 0 THEN EXIT; -- We've fully attributed this debit; stop looking at credits. END IF; END LOOP; -- End loop over credits -- IF debit_balance <> 0 THEN -- -- We weren't able to attribute this debit, or at least not -- all of it. Insert a row for the unattributed balance. -- attrib_count := attrib_count + 1; INSERT INTO acq.debit_attribution ( id, fund_debit, debit_amount, funding_source_credit, credit_amount ) VALUES ( attrib_count, deb.id, debit_balance, NULL, NULL ); END IF; END LOOP; -- End of loop over debits END;
Function: acq.audit_acq_lineitem_func()
Returns: trigger
Language: PLPGSQL
BEGIN INSERT INTO acq.acq_lineitem_history SELECT nextval('acq.acq_lineitem_pkey_seq'), now(), SUBSTR(TG_OP,1,1), OLD.*; RETURN NULL; END;
Function: acq.audit_acq_purchase_order_func()
Returns: trigger
Language: PLPGSQL
BEGIN INSERT INTO acq.acq_purchase_order_history SELECT nextval('acq.acq_purchase_order_pkey_seq'), now(), SUBSTR(TG_OP,1,1), OLD.*; RETURN NULL; END;
Function: acq.copy_fund_tags(new_fund_id integer, old_fund_id integer)
Returns: void
Language: PLPGSQL
DECLARE fund_tag_rec RECORD; BEGIN FOR fund_tag_rec IN SELECT * FROM acq.fund_tag_map WHERE fund=old_fund_id LOOP BEGIN INSERT INTO acq.fund_tag_map(fund, tag) VALUES(new_fund_id, fund_tag_rec.tag); EXCEPTION WHEN unique_violation THEN -- RAISE NOTICE 'Fund tag already propagated', old_fund.id; CONTINUE; END; END LOOP; RETURN; END;
Function: acq.create_acq_auditor(tbl text, sch text)
Returns: boolean
Language: PLPGSQL
BEGIN PERFORM acq.create_acq_seq(sch, tbl); PERFORM acq.create_acq_history(sch, tbl); PERFORM acq.create_acq_func(sch, tbl); PERFORM acq.create_acq_update_trigger(sch, tbl); PERFORM acq.create_acq_lifecycle(sch, tbl); RETURN TRUE; END;
Function: acq.create_acq_func(tbl text, sch text)
Returns: boolean
Language: PLPGSQL
BEGIN EXECUTE $$ CREATE OR REPLACE FUNCTION acq.audit_$$ || sch || $$_$$ || tbl || $$_func () RETURNS TRIGGER AS $func$ BEGIN INSERT INTO acq.$$ || sch || $$_$$ || tbl || $$_history SELECT nextval('acq.$$ || sch || $$_$$ || tbl || $$_pkey_seq'), now(), SUBSTR(TG_OP,1,1), OLD.*; RETURN NULL; END; $func$ LANGUAGE 'plpgsql'; $$; RETURN TRUE; END;
Function: acq.create_acq_history(tbl text, sch text)
Returns: boolean
Language: PLPGSQL
BEGIN EXECUTE $$ CREATE TABLE acq.$$ || sch || $$_$$ || tbl || $$_history ( audit_id BIGINT PRIMARY KEY, audit_time TIMESTAMP WITH TIME ZONE NOT NULL, audit_action TEXT NOT NULL, LIKE $$ || sch || $$.$$ || tbl || $$ ); $$; RETURN TRUE; END;
Function: acq.create_acq_lifecycle(tbl text, sch text)
Returns: boolean
Language: PLPGSQL
BEGIN EXECUTE $$ CREATE OR REPLACE VIEW acq.$$ || sch || $$_$$ || tbl || $$_lifecycle AS SELECT -1, now() as audit_time, '-' as audit_action, * FROM $$ || sch || $$.$$ || tbl || $$ UNION ALL SELECT * FROM acq.$$ || sch || $$_$$ || tbl || $$_history; $$; RETURN TRUE; END;
Function: acq.create_acq_seq(tbl text, sch text)
Returns: boolean
Language: PLPGSQL
BEGIN EXECUTE $$ CREATE SEQUENCE acq.$$ || sch || $$_$$ || tbl || $$_pkey_seq; $$; RETURN TRUE; END;
Function: acq.create_acq_update_trigger(tbl text, sch text)
Returns: boolean
Language: PLPGSQL
BEGIN EXECUTE $$ CREATE TRIGGER audit_$$ || sch || $$_$$ || tbl || $$_update_trigger AFTER UPDATE OR DELETE ON $$ || sch || $$.$$ || tbl || $$ FOR EACH ROW EXECUTE PROCEDURE acq.audit_$$ || sch || $$_$$ || tbl || $$_func (); $$; RETURN TRUE; END;
Function: acq.exchange_ratio(text, text, numeric)
Returns: numeric
Language: SQL
SELECT $3 * acq.exchange_ratio($1, $2);
Function: acq.exchange_ratio(to_ex text, from_ex text)
Returns: numeric
Language: PLPGSQL
DECLARE rat NUMERIC; BEGIN IF from_ex = to_ex THEN RETURN 1.0; END IF; SELECT ratio INTO rat FROM acq.exchange_rate WHERE from_currency = from_ex AND to_currency = to_ex; IF FOUND THEN RETURN rat; ELSE SELECT ratio INTO rat FROM acq.exchange_rate WHERE from_currency = to_ex AND to_currency = from_ex; IF FOUND THEN RETURN 1.0/rat; END IF; END IF; RETURN NULL; END;
Function: acq.extract_holding_attr_table(tag integer, lineitem text)
Returns: SET OF flat_lineitem_holding_subfield
Language: PLPGSQL
DECLARE counter INT; lida acq.flat_lineitem_holding_subfield%ROWTYPE; BEGIN SELECT COUNT(*) INTO counter FROM oils_xpath_table( 'id', 'marc', 'acq.lineitem', '//*[@tag="' || tag || '"]', 'id=' || lineitem ) as t(i int,c text); FOR i IN 1 .. counter LOOP FOR lida IN SELECT * FROM ( SELECT id,i,t,v FROM oils_xpath_table( 'id', 'marc', 'acq.lineitem', '//*[@tag="' || tag || '"][position()=' || i || ']/*/@code|' || '//*[@tag="' || tag || '"][position()=' || i || ']/*[@code]', 'id=' || lineitem ) as t(id int,t text,v text) )x LOOP RETURN NEXT lida; END LOOP; END LOOP; RETURN; END;
Function: acq.extract_provider_holding_data(lineitem_i integer)
Returns: SET OF flat_lineitem_detail
Language: PLPGSQL
DECLARE prov_i INT; tag_t TEXT; lida acq.flat_lineitem_detail%ROWTYPE; BEGIN SELECT provider INTO prov_i FROM acq.lineitem WHERE id = lineitem_i; IF NOT FOUND THEN RETURN; END IF; SELECT holding_tag INTO tag_t FROM acq.provider WHERE id = prov_i; IF NOT FOUND OR tag_t IS NULL THEN RETURN; END IF; FOR lida IN SELECT lineitem_i, h.holding, a.name, h.data FROM acq.extract_holding_attr_table( lineitem_i, tag_t ) h JOIN acq.provider_holding_subfield_map a USING (subfield) WHERE a.provider = prov_i LOOP RETURN NEXT lida; END LOOP; RETURN; END;
Function: acq.fap_limit_100()
Returns: trigger
Language: PLPGSQL
DECLARE -- total_percent numeric; -- BEGIN SELECT sum( percent ) INTO total_percent FROM acq.fund_allocation_percent AS fap WHERE fap.funding_source = NEW.funding_source; -- IF total_percent > 100 THEN RAISE EXCEPTION 'Total percentages exceed 100 for funding_source %', NEW.funding_source; ELSE RETURN NEW; END IF; END;
Function: acq.find_bad_fy()
Returns: SET OF record
Language: PLPGSQL
DECLARE first_row BOOLEAN; curr_year RECORD; prev_year RECORD; return_rec RECORD; BEGIN first_row := true; FOR curr_year in SELECT id, calendar, year, year_begin, year_end FROM acq.fiscal_year ORDER BY calendar, year_begin LOOP -- IF first_row THEN first_row := FALSE; ELSIF curr_year.calendar = prev_year.calendar THEN IF curr_year.year_begin > prev_year.year_end THEN -- This ugly kludge works around the fact that older -- versions of PostgreSQL don't support RETURN QUERY SELECT FOR return_rec IN SELECT prev_year.id, prev_year.year, 'Gap between fiscal years'::TEXT LOOP RETURN NEXT return_rec; END LOOP; ELSIF curr_year.year_begin < prev_year.year_end THEN FOR return_rec IN SELECT prev_year.id, prev_year.year, 'Overlapping fiscal years'::TEXT LOOP RETURN NEXT return_rec; END LOOP; ELSIF curr_year.year < prev_year.year THEN FOR return_rec IN SELECT prev_year.id, prev_year.year, 'Fiscal years out of order'::TEXT LOOP RETURN NEXT return_rec; END LOOP; END IF; END IF; -- prev_year := curr_year; END LOOP; -- RETURN; END;
Function: acq.fund_alloc_percent_val()
Returns: trigger
Language: PLPGSQL
-- DECLARE -- dummy int := 0; -- BEGIN SELECT 1 INTO dummy FROM acq.fund WHERE org = NEW.org AND code = NEW.fund_code LIMIT 1; -- IF dummy = 1 then RETURN NEW; ELSE RAISE EXCEPTION 'No fund exists for org % and code %', NEW.org, NEW.fund_code; END IF; END;
Function: acq.po_org_name_date_unique()
Returns: trigger
Language: PLPGSQL
DECLARE collision INT; BEGIN -- -- If order_date is not null, then make sure we don't have a collision -- on order_date (truncated to day), org, and name -- IF NEW.order_date IS NULL THEN RETURN NEW; END IF; -- -- In the WHERE clause, we compare the order_dates without regard to time of day. -- We use a pair of inequalities instead of comparing truncated dates so that the -- query can do an indexed range scan. -- SELECT 1 INTO collision FROM acq.purchase_order WHERE ordering_agency = NEW.ordering_agency AND name = NEW.name AND order_date >= date_trunc( 'day', NEW.order_date ) AND order_date < date_trunc( 'day', NEW.order_date ) + '1 day'::INTERVAL AND id <> NEW.id; -- IF collision IS NULL THEN -- okay, no collision RETURN NEW; ELSE -- collision; nip it in the bud RAISE EXCEPTION 'Colliding purchase orders: ordering_agency %, date %, name ''%''', NEW.ordering_agency, NEW.order_date, NEW.name; END IF; END;
Function: acq.propagate_funds_by_org_tree(include_desc integer, org_unit_id integer, user_id integer, old_year boolean)
Returns: void
Language: PLPGSQL
DECLARE -- new_id INT; old_fund RECORD; org_found BOOLEAN; -- BEGIN -- -- Sanity checks -- IF old_year IS NULL THEN RAISE EXCEPTION 'Input year argument is NULL'; ELSIF old_year NOT BETWEEN 2008 and 2200 THEN RAISE EXCEPTION 'Input year is out of range'; END IF; -- IF user_id IS NULL THEN RAISE EXCEPTION 'Input user id argument is NULL'; END IF; -- IF org_unit_id IS NULL THEN RAISE EXCEPTION 'Org unit id argument is NULL'; ELSE SELECT TRUE INTO org_found FROM actor.org_unit WHERE id = org_unit_id; -- IF org_found IS NULL THEN RAISE EXCEPTION 'Org unit id is invalid'; END IF; END IF; -- -- Loop over the applicable funds -- FOR old_fund in SELECT * FROM acq.fund WHERE year = old_year AND propagate AND ( ( include_desc AND org IN ( SELECT id FROM actor.org_unit_descendants( org_unit_id ) ) ) OR (NOT include_desc AND org = org_unit_id ) ) LOOP BEGIN INSERT INTO acq.fund ( org, name, year, currency_type, code, rollover, propagate, balance_warning_percent, balance_stop_percent ) VALUES ( old_fund.org, old_fund.name, old_year + 1, old_fund.currency_type, old_fund.code, old_fund.rollover, true, old_fund.balance_warning_percent, old_fund.balance_stop_percent ) RETURNING id INTO new_id; EXCEPTION WHEN unique_violation THEN --RAISE NOTICE 'Fund % already propagated', old_fund.id; CONTINUE; END; PERFORM acq.copy_fund_tags(old_fund.id,new_id); --RAISE NOTICE 'Propagating fund % to fund %', -- old_fund.code, new_id; END LOOP; END;
Function: acq.propagate_funds_by_org_unit(org_unit_id integer, user_id integer, old_year integer)
Returns: void
Language: SQL
SELECT acq.propagate_funds_by_org_tree( $1, $2, $3, FALSE );
Function: acq.purchase_order_name_default()
Returns: trigger
Language: PLPGSQL
BEGIN IF NEW.name IS NULL THEN NEW.name := NEW.id::TEXT; END IF; RETURN NEW; END;
Function: acq.rollover_funds_by_org_tree(include_desc integer, encumb_only integer, org_unit_id integer, user_id boolean, old_year boolean)
Returns: void
Language: PLPGSQL
DECLARE -- new_fund INT; new_year INT := old_year + 1; org_found BOOL; perm_ous BOOL; xfer_amount NUMERIC := 0; roll_fund RECORD; deb RECORD; detail RECORD; roll_distrib_forms BOOL; -- BEGIN -- -- Sanity checks -- IF old_year IS NULL THEN RAISE EXCEPTION 'Input year argument is NULL'; ELSIF old_year NOT BETWEEN 2008 and 2200 THEN RAISE EXCEPTION 'Input year is out of range'; END IF; -- IF user_id IS NULL THEN RAISE EXCEPTION 'Input user id argument is NULL'; END IF; -- IF org_unit_id IS NULL THEN RAISE EXCEPTION 'Org unit id argument is NULL'; ELSE -- -- Validate the org unit -- SELECT TRUE INTO org_found FROM actor.org_unit WHERE id = org_unit_id; -- IF org_found IS NULL THEN RAISE EXCEPTION 'Org unit id % is invalid', org_unit_id; ELSIF encumb_only THEN SELECT INTO perm_ous value::BOOL FROM actor.org_unit_ancestor_setting( 'acq.fund.allow_rollover_without_money', org_unit_id ); IF NOT FOUND OR NOT perm_ous THEN RAISE EXCEPTION 'Encumbrance-only rollover not permitted at org %', org_unit_id; END IF; END IF; END IF; -- -- Loop over the propagable funds to identify the details -- from the old fund plus the id of the new one, if it exists. -- FOR roll_fund in SELECT oldf.id AS old_fund, oldf.org, oldf.name, oldf.currency_type, oldf.code, oldf.rollover, newf.id AS new_fund_id FROM acq.fund AS oldf LEFT JOIN acq.fund AS newf ON ( oldf.code = newf.code AND oldf.org = newf.org ) WHERE oldf.year = old_year AND oldf.propagate AND newf.year = new_year AND ( ( include_desc AND oldf.org IN ( SELECT id FROM actor.org_unit_descendants( org_unit_id ) ) ) OR (NOT include_desc AND oldf.org = org_unit_id ) ) LOOP --RAISE NOTICE 'Processing fund %', roll_fund.old_fund; -- IF roll_fund.new_fund_id IS NULL THEN -- -- The old fund hasn't been propagated yet. Propagate it now. -- INSERT INTO acq.fund ( org, name, year, currency_type, code, rollover, propagate, balance_warning_percent, balance_stop_percent ) VALUES ( roll_fund.org, roll_fund.name, new_year, roll_fund.currency_type, roll_fund.code, true, true, roll_fund.balance_warning_percent, roll_fund.balance_stop_percent ) RETURNING id INTO new_fund; PERFORM acq.copy_fund_tags(roll_fund.id,new_fund); ELSE new_fund = roll_fund.new_fund_id; END IF; -- -- Determine the amount to transfer -- SELECT amount INTO xfer_amount FROM acq.fund_spent_balance WHERE fund = roll_fund.old_fund; -- IF xfer_amount <> 0 THEN IF NOT encumb_only AND roll_fund.rollover THEN -- -- Transfer balance from old fund to new -- --RAISE NOTICE 'Transferring % from fund % to %', xfer_amount, roll_fund.old_fund, new_fund; -- PERFORM acq.transfer_fund( roll_fund.old_fund, xfer_amount, new_fund, xfer_amount, user_id, 'Rollover' ); ELSE -- -- Transfer balance from old fund to the void -- -- RAISE NOTICE 'Transferring % from fund % to the void', xfer_amount, roll_fund.old_fund; -- PERFORM acq.transfer_fund( roll_fund.old_fund, xfer_amount, NULL, NULL, user_id, 'Rollover into the void' ); END IF; END IF; -- IF roll_fund.rollover THEN -- -- Move any lineitems from the old fund to the new one -- where the associated debit is an encumbrance. -- -- Any other tables tying expenditure details to funds should -- receive similar treatment. At this writing there are none. -- UPDATE acq.lineitem_detail SET fund = new_fund WHERE fund = roll_fund.old_fund -- this condition may be redundant AND fund_debit in ( SELECT id FROM acq.fund_debit WHERE fund = roll_fund.old_fund AND encumbrance ); -- -- Move encumbrance debits from the old fund to the new fund -- UPDATE acq.fund_debit SET fund = new_fund wHERE fund = roll_fund.old_fund AND encumbrance; END IF; -- Rollover distribution formulae funds SELECT INTO roll_distrib_forms value::BOOL FROM actor.org_unit_ancestor_setting( 'acq.fund.rollover_distrib_forms', org_unit_id ); IF roll_distrib_forms THEN UPDATE acq.distribution_formula_entry SET fund = roll_fund.new_fund_id WHERE fund = roll_fund.old_fund; END IF; -- -- Mark old fund as inactive, now that we've closed it -- UPDATE acq.fund SET active = FALSE WHERE id = roll_fund.old_fund; END LOOP; END;
Function: acq.rollover_funds_by_org_unit(encumb_only integer, org_unit_id integer, user_id integer, old_year boolean)
Returns: void
Language: SQL
SELECT acq.rollover_funds_by_org_tree( $1, $2, $3, $4, FALSE );
Function: acq.transfer_fund(xfer_note integer, user_id numeric, new_amount integer, new_fund numeric, old_amount integer, old_fund text)
Returns: void
Language: PLPGSQL
/* ------------------------------------------------------------------------------- Function to transfer money from one fund to another. A transfer is represented as a pair of entries in acq.fund_allocation, with a negative amount for the old (losing) fund and a positive amount for the new (gaining) fund. In some cases there may be more than one such pair of entries in order to pull the money from different funding sources, or more specifically from different funding source credits. For each such pair there is also an entry in acq.fund_transfer. Since funding_source is a non-nullable column in acq.fund_allocation, we must choose a funding source for the transferred money to come from. This choice must meet two constraints, so far as possible: 1. The amount transferred from a given funding source must not exceed the amount allocated to the old fund by the funding source. To that end we compare the amount being transferred to the amount allocated. 2. We shouldn't transfer money that has already been spent or encumbered, as defined by the funding attribution process. We attribute expenses to the oldest funding source credits first. In order to avoid transferring that attributed money, we reverse the priority, transferring from the newest funding source credits first. There can be no guarantee that this approach will avoid overcommitting a fund, but no other approach can do any better. In this context the age of a funding source credit is defined by the deadline_date for credits with deadline_dates, and by the effective_date for credits without deadline_dates, with the proviso that credits with deadline_dates are all considered "older" than those without. ---------- In the signature for this function, there is one last parameter commented out, named "funding_source_in". Correspondingly, the WHERE clause for the query driving the main loop has an OR clause commented out, which references the funding_source_in parameter. If these lines are uncommented, this function will allow the user optionally to restrict a fund transfer to a specified funding source. If the source parameter is left NULL, then there will be no such restriction. ------------------------------------------------------------------------------- */ DECLARE same_currency BOOLEAN; currency_ratio NUMERIC; old_fund_currency TEXT; old_remaining NUMERIC; -- in currency of old fund new_fund_currency TEXT; new_fund_active BOOLEAN; new_remaining NUMERIC; -- in currency of new fund curr_old_amt NUMERIC; -- in currency of old fund curr_new_amt NUMERIC; -- in currency of new fund source_addition NUMERIC; -- in currency of funding source source_deduction NUMERIC; -- in currency of funding source orig_allocated_amt NUMERIC; -- in currency of funding source allocated_amt NUMERIC; -- in currency of fund source RECORD; old_fund_row acq.fund%ROWTYPE; new_fund_row acq.fund%ROWTYPE; old_org_row actor.org_unit%ROWTYPE; new_org_row actor.org_unit%ROWTYPE; BEGIN -- -- Sanity checks -- IF old_fund IS NULL THEN RAISE EXCEPTION 'acq.transfer_fund: old fund id is NULL'; END IF; -- IF old_amount IS NULL THEN RAISE EXCEPTION 'acq.transfer_fund: amount to transfer is NULL'; END IF; -- -- The new fund and its amount must be both NULL or both not NULL. -- IF new_fund IS NOT NULL AND new_amount IS NULL THEN RAISE EXCEPTION 'acq.transfer_fund: amount to transfer to receiving fund is NULL'; END IF; -- IF new_fund IS NULL AND new_amount IS NOT NULL THEN RAISE EXCEPTION 'acq.transfer_fund: receiving fund is NULL, its amount is not NULL'; END IF; -- IF user_id IS NULL THEN RAISE EXCEPTION 'acq.transfer_fund: user id is NULL'; END IF; -- -- Initialize the amounts to be transferred, each denominated -- in the currency of its respective fund. They will be -- reduced on each iteration of the loop. -- old_remaining := old_amount; new_remaining := new_amount; -- -- RAISE NOTICE 'Transferring % in fund % to % in fund %', -- old_amount, old_fund, new_amount, new_fund; -- -- Get the currency types of the old and new funds. -- SELECT currency_type INTO old_fund_currency FROM acq.fund WHERE id = old_fund; -- IF old_fund_currency IS NULL THEN RAISE EXCEPTION 'acq.transfer_fund: old fund id % is not defined', old_fund; END IF; -- IF new_fund IS NOT NULL THEN SELECT currency_type, active INTO new_fund_currency, new_fund_active FROM acq.fund WHERE id = new_fund; -- IF new_fund_currency IS NULL THEN RAISE EXCEPTION 'acq.transfer_fund: new fund id % is not defined', new_fund; ELSIF NOT new_fund_active THEN -- -- No point in putting money into a fund from whence you can't spend it -- RAISE EXCEPTION 'acq.transfer_fund: new fund id % is inactive', new_fund; END IF; -- IF new_amount = old_amount THEN same_currency := true; currency_ratio := 1; ELSE -- -- We'll have to translate currency between funds. We presume that -- the calling code has already applied an appropriate exchange rate, -- so we'll apply the same conversion to each sub-transfer. -- same_currency := false; currency_ratio := new_amount / old_amount; END IF; END IF; -- Fetch old and new fund's information -- in order to construct the allocation notes SELECT INTO old_fund_row * FROM acq.fund WHERE id = old_fund; SELECT INTO old_org_row * FROM actor.org_unit WHERE id = old_fund_row.org; SELECT INTO new_fund_row * FROM acq.fund WHERE id = new_fund; SELECT INTO new_org_row * FROM actor.org_unit WHERE id = new_fund_row.org; -- -- Identify the funding source(s) from which we want to transfer the money. -- The principle is that we want to transfer the newest money first, because -- we spend the oldest money first. The priority for spending is defined -- by a sort of the view acq.ordered_funding_source_credit. -- FOR source in SELECT ofsc.id, ofsc.funding_source, ofsc.amount, ofsc.amount * acq.exchange_ratio( fs.currency_type, old_fund_currency ) AS converted_amt, fs.currency_type FROM acq.ordered_funding_source_credit AS ofsc, acq.funding_source fs WHERE ofsc.funding_source = fs.id and ofsc.funding_source IN ( SELECT funding_source FROM acq.fund_allocation WHERE fund = old_fund ) -- and -- ( -- ofsc.funding_source = funding_source_in -- OR funding_source_in IS NULL -- ) ORDER BY ofsc.sort_priority desc, ofsc.sort_date desc, ofsc.id desc LOOP -- -- Determine how much money the old fund got from this funding source, -- denominated in the currency types of the source and of the fund. -- This result may reflect transfers from previous iterations. -- SELECT COALESCE( sum( amount ), 0 ), COALESCE( sum( amount ) * acq.exchange_ratio( source.currency_type, old_fund_currency ), 0 ) INTO orig_allocated_amt, -- in currency of the source allocated_amt -- in currency of the old fund FROM acq.fund_allocation WHERE fund = old_fund and funding_source = source.funding_source; -- -- Determine how much to transfer from this credit, in the currency -- of the fund. Begin with the amount remaining to be attributed: -- curr_old_amt := old_remaining; -- -- Can't attribute more than was allocated from the fund: -- IF curr_old_amt > allocated_amt THEN curr_old_amt := allocated_amt; END IF; -- -- Can't attribute more than the amount of the current credit: -- IF curr_old_amt > source.converted_amt THEN curr_old_amt := source.converted_amt; END IF; -- curr_old_amt := trunc( curr_old_amt, 2 ); -- old_remaining := old_remaining - curr_old_amt; -- -- Determine the amount to be deducted, if any, -- from the old allocation. -- IF old_remaining > 0 THEN -- -- In this case we're using the whole allocation, so use that -- amount directly instead of applying a currency translation -- and thereby inviting round-off errors. -- source_deduction := - curr_old_amt; ELSE source_deduction := trunc( ( - curr_old_amt ) * acq.exchange_ratio( old_fund_currency, source.currency_type ), 2 ); END IF; -- IF source_deduction <> 0 THEN -- -- Insert negative allocation for old fund in fund_allocation, -- converted into the currency of the funding source -- INSERT INTO acq.fund_allocation ( funding_source, fund, amount, allocator, note ) VALUES ( source.funding_source, old_fund, source_deduction, user_id, 'Transfer to fund ' || new_fund_row.code || ' (' || new_fund_row.year || ') (' || new_org_row.shortname || ')' ); END IF; -- IF new_fund IS NOT NULL THEN -- -- Determine how much to add to the new fund, in -- its currency, and how much remains to be added: -- IF same_currency THEN curr_new_amt := curr_old_amt; ELSE IF old_remaining = 0 THEN -- -- This is the last iteration, so nothing should be left -- curr_new_amt := new_remaining; new_remaining := 0; ELSE curr_new_amt := trunc( curr_old_amt * currency_ratio, 2 ); new_remaining := new_remaining - curr_new_amt; END IF; END IF; -- -- Determine how much to add, if any, -- to the new fund's allocation. -- IF old_remaining > 0 THEN -- -- In this case we're using the whole allocation, so use that amount -- amount directly instead of applying a currency translation and -- thereby inviting round-off errors. -- source_addition := curr_new_amt; ELSIF source.currency_type = old_fund_currency THEN -- -- In this case we don't need a round trip currency translation, -- thereby inviting round-off errors: -- source_addition := curr_old_amt; ELSE source_addition := trunc( curr_new_amt * acq.exchange_ratio( new_fund_currency, source.currency_type ), 2 ); END IF; -- IF source_addition <> 0 THEN -- -- Insert positive allocation for new fund in fund_allocation, -- converted to the currency of the founding source -- INSERT INTO acq.fund_allocation ( funding_source, fund, amount, allocator, note ) VALUES ( source.funding_source, new_fund, source_addition, user_id, 'Transfer from fund ' || old_fund_row.code || ' (' || old_fund_row.year || ') (' || old_org_row.shortname || ')' ); END IF; END IF; -- IF trunc( curr_old_amt, 2 ) <> 0 OR trunc( curr_new_amt, 2 ) <> 0 THEN -- -- Insert row in fund_transfer, using amounts in the currency of the funds -- INSERT INTO acq.fund_transfer ( src_fund, src_amount, dest_fund, dest_amount, transfer_user, note, funding_source_credit ) VALUES ( old_fund, trunc( curr_old_amt, 2 ), new_fund, trunc( curr_new_amt, 2 ), user_id, xfer_note, source.id ); END IF; -- if old_remaining <= 0 THEN EXIT; -- Nothing more to be transferred END IF; END LOOP; END;
Schema action
Table: action.aged_circulation
F-Key | Name | Type | Description |
---|---|---|---|
usr_post_code | text | ||
usr_home_ou | integer | NOT NULL | |
usr_profile | integer | NOT NULL | |
usr_birth_year | integer | ||
copy_call_number | integer | NOT NULL | |
copy_owning_lib | integer | NOT NULL | |
copy_circ_lib | integer | NOT NULL | |
copy_bib_record | bigint | NOT NULL | |
id | bigint | PRIMARY KEY | |
xact_start | timestamp with time zone | NOT NULL | |
xact_finish | timestamp with time zone | ||
unrecovered | boolean | ||
target_copy | bigint | NOT NULL | |
circ_lib | integer | NOT NULL | |
circ_staff | integer | NOT NULL | |
checkin_staff | integer | ||
checkin_lib | integer | ||
renewal_remaining | integer | NOT NULL | |
grace_period | interval | NOT NULL | |
due_date | timestamp with time zone | ||
stop_fines_time | timestamp with time zone | ||
checkin_time | timestamp with time zone | ||
create_time | timestamp with time zone | NOT NULL | |
duration | interval | ||
fine_interval | interval | NOT NULL | |
recurring_fine | numeric(6,2) | ||
max_fine | numeric(6,2) | ||
phone_renewal | boolean | NOT NULL | |
desk_renewal | boolean | NOT NULL | |
opac_renewal | boolean | NOT NULL | |
duration_rule | text | NOT NULL | |
recurring_fine_rule | text | NOT NULL | |
max_fine_rule | text | NOT NULL | |
stop_fines | text | ||
workstation | integer | ||
checkin_workstation | integer | ||
copy_location | integer | NOT NULL | |
checkin_scan_time | timestamp with time zone | ||
auto_renewal | boolean | NOT NULL | |
auto_renewal_remaining | integer | ||
parent_circ | bigint |
Table: action.aged_hold_request
F-Key | Name | Type | Description |
---|---|---|---|
usr_post_code | text | ||
usr_home_ou | integer | NOT NULL | |
usr_profile | integer | NOT NULL | |
usr_birth_year | integer | ||
staff_placed | boolean | NOT NULL | |
id | integer | PRIMARY KEY | |
request_time | timestamp with time zone | NOT NULL | |
capture_time | timestamp with time zone | ||
fulfillment_time | timestamp with time zone | ||
checkin_time | timestamp with time zone | ||
return_time | timestamp with time zone | ||
prev_check_time | timestamp with time zone | ||
expire_time | timestamp with time zone | ||
cancel_time | timestamp with time zone | ||
cancel_cause | integer | ||
cancel_note | text | ||
target | bigint | NOT NULL | |
current_copy | bigint | ||
fulfillment_staff | integer | ||
fulfillment_lib | integer | ||
request_lib | integer | NOT NULL | |
selection_ou | integer | NOT NULL | |
selection_depth | integer | NOT NULL | |
pickup_lib | integer | NOT NULL | |
hold_type | text | ||
holdable_formats | text | ||
phone_notify | boolean | NOT NULL | |
email_notify | boolean | NOT NULL | |
sms_notify | boolean | NOT NULL | |
frozen | boolean | NOT NULL | |
thaw_date | timestamp with time zone | ||
shelf_time | timestamp with time zone | ||
cut_in_line | boolean | ||
mint_condition | boolean | NOT NULL | |
shelf_expire_time | timestamp with time zone | ||
current_shelf_lib | integer | ||
behind_desk | boolean | NOT NULL | |
hopeless_date | timestamp with time zone |
View: action.all_circulation
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
usr_post_code | text | ||
usr_home_ou | integer | ||
usr_profile | integer | ||
usr_birth_year | integer | ||
copy_call_number | bigint | ||
copy_location | integer | ||
copy_owning_lib | integer | ||
copy_circ_lib | integer | ||
copy_bib_record | bigint | ||
xact_start | timestamp with time zone | ||
xact_finish | timestamp with time zone | ||
target_copy | bigint | ||
circ_lib | integer | ||
circ_staff | integer | ||
checkin_staff | integer | ||
checkin_lib | integer | ||
renewal_remaining | integer | ||
grace_period | interval | ||
due_date | timestamp with time zone | ||
stop_fines_time | timestamp with time zone | ||
checkin_time | timestamp with time zone | ||
create_time | timestamp with time zone | ||
duration | interval | ||
fine_interval | interval | ||
recurring_fine | numeric(6,2) | ||
max_fine | numeric(6,2) | ||
phone_renewal | boolean | ||
desk_renewal | boolean | ||
opac_renewal | boolean | ||
duration_rule | text | ||
recurring_fine_rule | text | ||
max_fine_rule | text | ||
stop_fines | text | ||
workstation | integer | ||
checkin_workstation | integer | ||
checkin_scan_time | timestamp with time zone | ||
parent_circ | bigint | ||
auto_renewal | boolean | ||
auto_renewal_remaining | integer | ||
usr | integer |
SELECT aged_circulation.id , aged_circulation.usr_post_code , aged_circulation.usr_home_ou , aged_circulation.usr_profile , aged_circulation.usr_birth_year , aged_circulation.copy_call_number , aged_circulation.copy_location , aged_circulation.copy_owning_lib , aged_circulation.copy_circ_lib , aged_circulation.copy_bib_record , aged_circulation.xact_start , aged_circulation.xact_finish , aged_circulation.target_copy , aged_circulation.circ_lib , aged_circulation.circ_staff , aged_circulation.checkin_staff , aged_circulation.checkin_lib , aged_circulation.renewal_remaining , aged_circulation.grace_period , aged_circulation.due_date , aged_circulation.stop_fines_time , aged_circulation.checkin_time , aged_circulation.create_time , aged_circulation.duration , aged_circulation.fine_interval , aged_circulation.recurring_fine , aged_circulation.max_fine , aged_circulation.phone_renewal , aged_circulation.desk_renewal , aged_circulation.opac_renewal , aged_circulation.duration_rule , aged_circulation.recurring_fine_rule , aged_circulation.max_fine_rule , aged_circulation.stop_fines , aged_circulation.workstation , aged_circulation.checkin_workstation , aged_circulation.checkin_scan_time , aged_circulation.parent_circ , aged_circulation.auto_renewal , aged_circulation.auto_renewal_remaining , NULL::integer AS usr FROM action.aged_circulation UNION ALL SELECT DISTINCT circ.id , COALESCE (a.post_code , b.post_code ) AS usr_post_code , p.home_ou AS usr_home_ou , p.profile AS usr_profile , (date_part ('year'::text , p.dob ) )::integer AS usr_birth_year , cp.call_number AS copy_call_number , circ.copy_location , cn.owning_lib AS copy_owning_lib , cp.circ_lib AS copy_circ_lib , cn.record AS copy_bib_record , circ.xact_start , circ.xact_finish , circ.target_copy , circ.circ_lib , circ.circ_staff , circ.checkin_staff , circ.checkin_lib , circ.renewal_remaining , circ.grace_period , circ.due_date , circ.stop_fines_time , circ.checkin_time , circ.create_time , circ.duration , circ.fine_interval , circ.recurring_fine , circ.max_fine , circ.phone_renewal , circ.desk_renewal , circ.opac_renewal , circ.duration_rule , circ.recurring_fine_rule , circ.max_fine_rule , circ.stop_fines , circ.workstation , circ.checkin_workstation , circ.checkin_scan_time , circ.parent_circ , circ.auto_renewal , circ.auto_renewal_remaining , circ.usr FROM ( ( ( ( (action.circulation circ JOIN asset.copy cp ON ( (circ.target_copy = cp.id) ) ) JOIN asset.call_number cn ON ( (cp.call_number = cn.id) ) ) JOIN actor.usr p ON ( (circ.usr = p.id) ) ) LEFT JOIN actor.usr_address a ON ( (p.mailing_address = a.id) ) ) LEFT JOIN actor.usr_address b ON ( (p.billing_address = b.id) ) );
View: action.all_circulation_combined_types
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
xact_start | timestamp with time zone | ||
circ_lib | integer | ||
circ_staff | integer | ||
create_time | timestamp with time zone | ||
item_type | text | ||
circ_type | text |
SELECT acirc.id , acirc.xact_start , acirc.circ_lib , acirc.circ_staff , acirc.create_time , ac_acirc.circ_modifier AS item_type , 'regular_circ'::text AS circ_type FROM action.circulation acirc , asset.copy ac_acirc WHERE (acirc.target_copy = ac_acirc.id) UNION ALL SELECT (ancc.id)::bigint AS id , ancc.circ_time AS xact_start , ancc.circ_lib , ancc.staff AS circ_staff , ancc.circ_time AS create_time , cnct_ancc.name AS item_type , 'non-cat_circ'::text AS circ_type FROM action.non_cataloged_circulation ancc , config.non_cataloged_type cnct_ancc WHERE (ancc.item_type = cnct_ancc.id) UNION ALL SELECT (aihu.id)::bigint AS id , aihu.use_time AS xact_start , aihu.org_unit AS circ_lib , aihu.staff AS circ_staff , aihu.use_time AS create_time , ac_aihu.circ_modifier AS item_type , 'in-house_use'::text AS circ_type FROM action.in_house_use aihu , asset.copy ac_aihu WHERE (aihu.item = ac_aihu.id) UNION ALL SELECT (ancihu.id)::bigint AS id , ancihu.use_time AS xact_start , ancihu.org_unit AS circ_lib , ancihu.staff AS circ_staff , ancihu.use_time AS create_time , cnct_ancihu.name AS item_type , 'non-cat-in-house_use'::text AS circ_type FROM action.non_cat_in_house_use ancihu , config.non_cataloged_type cnct_ancihu WHERE (ancihu.item_type = cnct_ancihu.id) UNION ALL SELECT aacirc.id , aacirc.xact_start , aacirc.circ_lib , aacirc.circ_staff , aacirc.create_time , ac_aacirc.circ_modifier AS item_type , 'aged_circ'::text AS circ_type FROM action.aged_circulation aacirc , asset.copy ac_aacirc WHERE (aacirc.target_copy = ac_aacirc.id);
View: action.all_circulation_slim
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
usr | integer | ||
xact_start | timestamp with time zone | ||
xact_finish | timestamp with time zone | ||
unrecovered | boolean | ||
target_copy | bigint | ||
circ_lib | integer | ||
circ_staff | integer | ||
checkin_staff | integer | ||
checkin_lib | integer | ||
renewal_remaining | integer | ||
grace_period | interval | ||
due_date | timestamp with time zone | ||
stop_fines_time | timestamp with time zone | ||
checkin_time | timestamp with time zone | ||
create_time | timestamp with time zone | ||
duration | interval | ||
fine_interval | interval | ||
recurring_fine | numeric(6,2) | ||
max_fine | numeric(6,2) | ||
phone_renewal | boolean | ||
desk_renewal | boolean | ||
opac_renewal | boolean | ||
duration_rule | text | ||
recurring_fine_rule | text | ||
max_fine_rule | text | ||
stop_fines | text | ||
workstation | integer | ||
checkin_workstation | integer | ||
copy_location | integer | ||
checkin_scan_time | timestamp with time zone | ||
auto_renewal | boolean | ||
auto_renewal_remaining | integer | ||
parent_circ | bigint |
SELECT circulation.id , circulation.usr , circulation.xact_start , circulation.xact_finish , circulation.unrecovered , circulation.target_copy , circulation.circ_lib , circulation.circ_staff , circulation.checkin_staff , circulation.checkin_lib , circulation.renewal_remaining , circulation.grace_period , circulation.due_date , circulation.stop_fines_time , circulation.checkin_time , circulation.create_time , circulation.duration , circulation.fine_interval , circulation.recurring_fine , circulation.max_fine , circulation.phone_renewal , circulation.desk_renewal , circulation.opac_renewal , circulation.duration_rule , circulation.recurring_fine_rule , circulation.max_fine_rule , circulation.stop_fines , circulation.workstation , circulation.checkin_workstation , circulation.copy_location , circulation.checkin_scan_time , circulation.auto_renewal , circulation.auto_renewal_remaining , circulation.parent_circ FROM action.circulation UNION ALL SELECT aged_circulation.id , NULL::integer AS usr , aged_circulation.xact_start , aged_circulation.xact_finish , aged_circulation.unrecovered , aged_circulation.target_copy , aged_circulation.circ_lib , aged_circulation.circ_staff , aged_circulation.checkin_staff , aged_circulation.checkin_lib , aged_circulation.renewal_remaining , aged_circulation.grace_period , aged_circulation.due_date , aged_circulation.stop_fines_time , aged_circulation.checkin_time , aged_circulation.create_time , aged_circulation.duration , aged_circulation.fine_interval , aged_circulation.recurring_fine , aged_circulation.max_fine , aged_circulation.phone_renewal , aged_circulation.desk_renewal , aged_circulation.opac_renewal , aged_circulation.duration_rule , aged_circulation.recurring_fine_rule , aged_circulation.max_fine_rule , aged_circulation.stop_fines , aged_circulation.workstation , aged_circulation.checkin_workstation , aged_circulation.copy_location , aged_circulation.checkin_scan_time , aged_circulation.auto_renewal , aged_circulation.auto_renewal_remaining , aged_circulation.parent_circ FROM action.aged_circulation;
View: action.all_hold_request
F-Key | Name | Type | Description |
---|---|---|---|
usr_post_code | text | ||
usr_home_ou | integer | ||
usr_profile | integer | ||
usr_birth_year | integer | ||
staff_placed | boolean | ||
id | integer | ||
request_time | timestamp with time zone | ||
capture_time | timestamp with time zone | ||
fulfillment_time | timestamp with time zone | ||
checkin_time | timestamp with time zone | ||
return_time | timestamp with time zone | ||
prev_check_time | timestamp with time zone | ||
expire_time | timestamp with time zone | ||
cancel_time | timestamp with time zone | ||
cancel_cause | integer | ||
cancel_note | text | ||
target | bigint | ||
current_copy | bigint | ||
fulfillment_staff | integer | ||
fulfillment_lib | integer | ||
request_lib | integer | ||
selection_ou | integer | ||
selection_depth | integer | ||
pickup_lib | integer | ||
hold_type | text | ||
holdable_formats | text | ||
phone_notify | boolean | ||
email_notify | boolean | ||
sms_notify | boolean | ||
frozen | boolean | ||
thaw_date | timestamp with time zone | ||
shelf_time | timestamp with time zone | ||
cut_in_line | boolean | ||
mint_condition | boolean | ||
shelf_expire_time | timestamp with time zone | ||
current_shelf_lib | integer | ||
behind_desk | boolean |
SELECT DISTINCT COALESCE (a.post_code , b.post_code ) AS usr_post_code , p.home_ou AS usr_home_ou , p.profile AS usr_profile , (date_part ('year'::text , p.dob ) )::integer AS usr_birth_year , (ahr.requestor <> ahr.usr) AS staff_placed , ahr.id , ahr.request_time , ahr.capture_time , ahr.fulfillment_time , ahr.checkin_time , ahr.return_time , ahr.prev_check_time , ahr.expire_time , ahr.cancel_time , ahr.cancel_cause , ahr.cancel_note , ahr.target , ahr.current_copy , ahr.fulfillment_staff , ahr.fulfillment_lib , ahr.request_lib , ahr.selection_ou , ahr.selection_depth , ahr.pickup_lib , ahr.hold_type , ahr.holdable_formats , CASE WHEN (ahr.phone_notify IS NULL) THEN false WHEN (ahr.phone_notify = ''::text) THEN false ELSE true END AS phone_notify , ahr.email_notify , CASE WHEN (ahr.sms_notify IS NULL) THEN false WHEN (ahr.sms_notify = ''::text) THEN false ELSE true END AS sms_notify , ahr.frozen , ahr.thaw_date , ahr.shelf_time , ahr.cut_in_line , ahr.mint_condition , ahr.shelf_expire_time , ahr.current_shelf_lib , ahr.behind_desk FROM ( ( (action.hold_request ahr JOIN actor.usr p ON ( (ahr.usr = p.id) ) ) LEFT JOIN actor.usr_address a ON ( (p.mailing_address = a.id) ) ) LEFT JOIN actor.usr_address b ON ( (p.billing_address = b.id) ) ) UNION ALL SELECT aged_hold_request.usr_post_code , aged_hold_request.usr_home_ou , aged_hold_request.usr_profile , aged_hold_request.usr_birth_year , aged_hold_request.staff_placed , aged_hold_request.id , aged_hold_request.request_time , aged_hold_request.capture_time , aged_hold_request.fulfillment_time , aged_hold_request.checkin_time , aged_hold_request.return_time , aged_hold_request.prev_check_time , aged_hold_request.expire_time , aged_hold_request.cancel_time , aged_hold_request.cancel_cause , aged_hold_request.cancel_note , aged_hold_request.target , aged_hold_request.current_copy , aged_hold_request.fulfillment_staff , aged_hold_request.fulfillment_lib , aged_hold_request.request_lib , aged_hold_request.selection_ou , aged_hold_request.selection_depth , aged_hold_request.pickup_lib , aged_hold_request.hold_type , aged_hold_request.holdable_formats , aged_hold_request.phone_notify , aged_hold_request.email_notify , aged_hold_request.sms_notify , aged_hold_request.frozen , aged_hold_request.thaw_date , aged_hold_request.shelf_time , aged_hold_request.cut_in_line , aged_hold_request.mint_condition , aged_hold_request.shelf_expire_time , aged_hold_request.current_shelf_lib , aged_hold_request.behind_desk FROM action.aged_hold_request;
Table: action.archive_actor_stat_cat
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
xact | bigint | NOT NULL | |
stat_cat | integer | NOT NULL | |
value | text | NOT NULL |
Table: action.archive_asset_stat_cat
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
xact | bigint | NOT NULL | |
stat_cat | integer | NOT NULL | |
value | text | NOT NULL |
Table: action.batch_hold_event
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.usr.id | staff | integer | NOT NULL |
container.user_bucket.id | bucket | integer | NOT NULL |
target | integer | NOT NULL | |
hold_type | text | NOT NULL DEFAULT 'T'::text | |
run_date | timestamp with time zone | NOT NULL DEFAULT now() | |
cancelled | timestamp with time zone |
Tables referencing this one via Foreign Key Constraints:
Table: action.batch_hold_event_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
action.batch_hold_event.id | batch_hold_event | integer | NOT NULL |
action.hold_request.id | hold | integer | NOT NULL |
View: action.billable_circulations
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
usr | integer | ||
xact_start | timestamp with time zone | ||
xact_finish | timestamp with time zone | ||
unrecovered | boolean | ||
target_copy | bigint | ||
circ_lib | integer | ||
circ_staff | integer | ||
checkin_staff | integer | ||
checkin_lib | integer | ||
renewal_remaining | integer | ||
grace_period | interval | ||
due_date | timestamp with time zone | ||
stop_fines_time | timestamp with time zone | ||
checkin_time | timestamp with time zone | ||
create_time | timestamp with time zone | ||
duration | interval | ||
fine_interval | interval | ||
recurring_fine | numeric(6,2) | ||
max_fine | numeric(6,2) | ||
phone_renewal | boolean | ||
desk_renewal | boolean | ||
opac_renewal | boolean | ||
duration_rule | text | ||
recurring_fine_rule | text | ||
max_fine_rule | text | ||
stop_fines | text | ||
workstation | integer | ||
checkin_workstation | integer | ||
copy_location | integer | ||
checkin_scan_time | timestamp with time zone | ||
auto_renewal | boolean | ||
auto_renewal_remaining | integer | ||
parent_circ | bigint |
SELECT circulation.id , circulation.usr , circulation.xact_start , circulation.xact_finish , circulation.unrecovered , circulation.target_copy , circulation.circ_lib , circulation.circ_staff , circulation.checkin_staff , circulation.checkin_lib , circulation.renewal_remaining , circulation.grace_period , circulation.due_date , circulation.stop_fines_time , circulation.checkin_time , circulation.create_time , circulation.duration , circulation.fine_interval , circulation.recurring_fine , circulation.max_fine , circulation.phone_renewal , circulation.desk_renewal , circulation.opac_renewal , circulation.duration_rule , circulation.recurring_fine_rule , circulation.max_fine_rule , circulation.stop_fines , circulation.workstation , circulation.checkin_workstation , circulation.copy_location , circulation.checkin_scan_time , circulation.auto_renewal , circulation.auto_renewal_remaining , circulation.parent_circ FROM action.circulation WHERE (circulation.xact_finish IS NULL);
Table: action.circulation
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY DEFAULT nextval('money.billable_xact_id_seq'::regclass) | |
actor.usr.id | usr | integer | NOT NULL |
xact_start | timestamp with time zone | NOT NULL DEFAULT now() | |
xact_finish | timestamp with time zone | ||
unrecovered | boolean | ||
target_copy | bigint | NOT NULL | |
actor.org_unit.id | circ_lib | integer | NOT NULL |
circ_staff | integer | NOT NULL | |
checkin_staff | integer | ||
checkin_lib | integer | ||
renewal_remaining | integer | NOT NULL | |
grace_period | interval | NOT NULL | |
due_date | timestamp with time zone | ||
stop_fines_time | timestamp with time zone | ||
checkin_time | timestamp with time zone | ||
create_time | timestamp with time zone | NOT NULL DEFAULT now() | |
duration | interval | ||
fine_interval | interval | NOT NULL DEFAULT '1 day'::interval | |
recurring_fine | numeric(6,2) | ||
max_fine | numeric(6,2) | ||
phone_renewal | boolean | NOT NULL DEFAULT false | |
desk_renewal | boolean | NOT NULL DEFAULT false | |
opac_renewal | boolean | NOT NULL DEFAULT false | |
duration_rule | text | NOT NULL | |
recurring_fine_rule | text | NOT NULL | |
max_fine_rule | text | NOT NULL | |
stop_fines | text | ||
actor.workstation.id | workstation | integer | |
actor.workstation.id | checkin_workstation | integer | |
asset.copy_location.id | copy_location | integer | NOT NULL DEFAULT 1 |
checkin_scan_time | timestamp with time zone | ||
auto_renewal | boolean | NOT NULL DEFAULT false | |
auto_renewal_remaining | integer | ||
action.circulation.id | parent_circ | bigint |
Table action.circulation Inherits billable_xact,
Name | Constraint |
---|---|
circulation_stop_fines_check | CHECK ((stop_fines = ANY (ARRAY['CHECKIN'::text, 'CLAIMSRETURNED'::text, 'LOST'::text, 'MAXFINES'::text, 'RENEW'::text, 'LONGOVERDUE'::text, 'CLAIMSNEVERCHECKEDOUT'::text]))) |
Tables referencing this one via Foreign Key Constraints:
action_circulation_target_copy_idx target_copy circ_all_usr_idx usr circ_checkin_staff_idx checkin_staff circ_checkin_time checkin_time) WHERE (checkin_time IS NOT NULL circ_circ_lib_idx circ_lib circ_circ_staff_idx circ_staff circ_open_date_idx xact_start) WHERE (xact_finish IS NULL circ_open_xacts_idx usr) WHERE (xact_finish IS NULL circ_outstanding_idx usr) WHERE (checkin_time IS NULLTable: action.circulation_limit_group_map
F-Key | Name | Type | Description |
---|---|---|---|
action.circulation.id | circ | bigint | PRIMARY KEY |
config.circ_limit_group.id | limit_group | integer | PRIMARY KEY |
Table: action.curbside
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.usr.id | patron | integer | NOT NULL |
actor.org_unit.id | org | integer | NOT NULL |
slot | timestamp with time zone | ||
staged | timestamp with time zone | ||
actor.usr.id | stage_staff | integer | |
arrival | timestamp with time zone | ||
delivered | timestamp with time zone | ||
actor.usr.id | delivery_staff | integer | |
notes | text |
Table: action.emergency_closing
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.usr.id | creator | integer | NOT NULL |
create_time | timestamp with time zone | NOT NULL DEFAULT now() | |
process_start_time | timestamp with time zone | ||
process_end_time | timestamp with time zone | ||
last_update_time | timestamp with time zone |
Tables referencing this one via Foreign Key Constraints:
Table: action.emergency_closing_circulation
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
action.emergency_closing.id | emergency_closing | integer | NOT NULL |
action.circulation.id | circulation | integer | NOT NULL |
original_due_date | timestamp with time zone | ||
process_time | timestamp with time zone |
Table: action.emergency_closing_hold
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
action.emergency_closing.id | emergency_closing | integer | NOT NULL |
action.hold_request.id | hold | integer | NOT NULL |
original_shelf_expire_time | timestamp with time zone | ||
process_time | timestamp with time zone |
Table: action.emergency_closing_reservation
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
action.emergency_closing.id | emergency_closing | integer | NOT NULL |
booking.reservation.id | reservation | integer | NOT NULL |
original_end_time | timestamp with time zone | ||
process_time | timestamp with time zone |
View: action.emergency_closing_status
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
creator | integer | ||
create_time | timestamp with time zone | ||
process_start_time | timestamp with time zone | ||
process_end_time | timestamp with time zone | ||
last_update_time | timestamp with time zone | ||
circulations | bigint | ||
circulations_complete | bigint | ||
reservations | bigint | ||
reservations_complete | bigint | ||
holds | bigint | ||
holds_complete | bigint |
SELECT e.id , e.creator , e.create_time , e.process_start_time , e.process_end_time , e.last_update_time , COALESCE (c.count , (0)::bigint ) AS circulations , COALESCE (c.completed , (0)::bigint ) AS circulations_complete , COALESCE (b.count , (0)::bigint ) AS reservations , COALESCE (b.completed , (0)::bigint ) AS reservations_complete , COALESCE (h.count , (0)::bigint ) AS holds , COALESCE (h.completed , (0)::bigint ) AS holds_complete FROM ( ( (action.emergency_closing e LEFT JOIN ( SELECT emergency_closing_circulation.emergency_closing , count (*) AS count , sum ( ( (emergency_closing_circulation.process_time IS NOT NULL) )::integer ) AS completed FROM action.emergency_closing_circulation GROUP BY emergency_closing_circulation.emergency_closing ) c ON ( (c.emergency_closing = e.id) ) ) LEFT JOIN ( SELECT emergency_closing_reservation.emergency_closing , count (*) AS count , sum ( ( (emergency_closing_reservation.process_time IS NOT NULL) )::integer ) AS completed FROM action.emergency_closing_reservation GROUP BY emergency_closing_reservation.emergency_closing ) b ON ( (b.emergency_closing = e.id) ) ) LEFT JOIN ( SELECT emergency_closing_hold.emergency_closing , count (*) AS count , sum ( ( (emergency_closing_hold.process_time IS NOT NULL) )::integer ) AS completed FROM action.emergency_closing_hold GROUP BY emergency_closing_hold.emergency_closing ) h ON ( (h.emergency_closing = e.id) ) );
Table: action.fieldset
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
action.fieldset_group.id | fieldset_group | integer | |
actor.usr.id | owner | integer | NOT NULL |
actor.org_unit.id | owning_lib | integer | UNIQUE#1 NOT NULL |
status | text | NOT NULL | |
creation_time | timestamp with time zone | NOT NULL DEFAULT now() | |
scheduled_time | timestamp with time zone | ||
applied_time | timestamp with time zone | ||
classname | text | NOT NULL | |
name | text | UNIQUE#1 NOT NULL | |
error_msg | text | ||
query.stored_query.id | stored_query | integer | |
pkey_value | text |
Name | Constraint |
---|---|
fieldset_one_or_the_other | CHECK ((((stored_query IS NOT NULL) AND (pkey_value IS NULL)) OR ((pkey_value IS NOT NULL) AND (stored_query IS NULL)))) |
valid_status | CHECK ((status = ANY (ARRAY['PENDING'::text, 'APPLIED'::text, 'ERROR'::text]))) |
Tables referencing this one via Foreign Key Constraints:
action_fieldset_sched_time_idx scheduled_time action_owner_idx ownerTable: action.fieldset_col_val
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
action.fieldset.id | fieldset | integer | UNIQUE#1 NOT NULL |
col | text | UNIQUE#1 NOT NULL | |
val | text |
Table: action.fieldset_group
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | NOT NULL | |
create_time | timestamp with time zone | NOT NULL DEFAULT now() | |
complete_time | timestamp with time zone | ||
container | integer | ||
container_type | text | ||
can_rollback | boolean | DEFAULT true | |
action.fieldset_group.id | rollback_group | integer | |
rollback_time | timestamp with time zone | ||
actor.usr.id | creator | integer | NOT NULL |
actor.org_unit.id | owning_lib | integer | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: action.hold_copy_map
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
action.hold_request.id | hold | integer | UNIQUE#1 NOT NULL |
target_copy | bigint | UNIQUE#1 NOT NULL | |
proximity | numeric |
Table: action.hold_notification
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
action.hold_request.id | hold | integer | NOT NULL |
actor.usr.id | notify_staff | integer | |
notify_time | timestamp with time zone | NOT NULL DEFAULT now() | |
method | text | NOT NULL | |
note | text |
Table: action.hold_request
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
request_time | timestamp with time zone | NOT NULL DEFAULT now() | |
capture_time | timestamp with time zone | ||
fulfillment_time | timestamp with time zone | ||
checkin_time | timestamp with time zone | ||
return_time | timestamp with time zone | ||
prev_check_time | timestamp with time zone | ||
expire_time | timestamp with time zone | ||
cancel_time | timestamp with time zone | ||
action.hold_request_cancel_cause.id | cancel_cause | integer | |
cancel_note | text | ||
target | bigint | NOT NULL | |
current_copy | bigint | ||
actor.usr.id | fulfillment_staff | integer | |
actor.org_unit.id | fulfillment_lib | integer | |
actor.org_unit.id | request_lib | integer | NOT NULL |
actor.usr.id | requestor | integer | NOT NULL |
actor.usr.id | usr | integer | NOT NULL |
selection_ou | integer | NOT NULL | |
selection_depth | integer | NOT NULL | |
actor.org_unit.id | pickup_lib | integer | NOT NULL |
config.hold_type.hold_type | hold_type | text | |
holdable_formats | text | ||
phone_notify | text | ||
email_notify | boolean | NOT NULL DEFAULT false | |
sms_notify | text | ||
config.sms_carrier.id | sms_carrier | integer | |
frozen | boolean | NOT NULL DEFAULT false | |
thaw_date | timestamp with time zone | ||
shelf_time | timestamp with time zone | ||
cut_in_line | boolean | ||
mint_condition | boolean | NOT NULL DEFAULT true | |
shelf_expire_time | timestamp with time zone | ||
actor.org_unit.id | current_shelf_lib | integer | |
behind_desk | boolean | NOT NULL DEFAULT false | |
hopeless_date | timestamp with time zone | ||
acq.user_request.id | acq_request | integer |
Name | Constraint |
---|---|
sms_check | CHECK (((sms_notify IS NULL) OR (sms_carrier IS NOT NULL))) |
Tables referencing this one via Foreign Key Constraints:
hold_fulfillment_time_idx fulfillment_time) WHERE (fulfillment_time IS NOT NULL hold_request_copy_capture_time_idx current_copy, capture_time hold_request_current_copy_before_cap_idx current_copy) WHERE ((capture_time IS NULL) AND (cancel_time IS NULL) hold_request_current_copy_idx current_copy hold_request_fulfillment_staff_idx fulfillment_staff hold_request_open_captured_shelf_lib_idx current_shelf_lib) WHERE ((capture_time IS NOT NULL) AND (fulfillment_time IS NULL) AND (pickup_lib <> current_shelf_lib) hold_request_open_idx id) WHERE ((cancel_time IS NULL) AND (fulfillment_time IS NULL) hold_request_pickup_lib_idx pickup_lib hold_request_prev_check_time_idx prev_check_time hold_request_requestor_idx requestor hold_request_target_idx target hold_request_time_idx request_time hold_request_usr_idx usrTable: action.hold_request_cancel_cause
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
label | text | UNIQUE |
Tables referencing this one via Foreign Key Constraints:
Table: action.hold_request_note
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
action.hold_request.id | hold | bigint | NOT NULL |
title | text | NOT NULL | |
body | text | NOT NULL | |
slip | boolean | NOT NULL DEFAULT false | |
pub | boolean | NOT NULL DEFAULT false | |
staff | boolean | NOT NULL DEFAULT false |
Table: action.hold_transit_copy
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | PRIMARY KEY DEFAULT nextval('action.transit_copy_id_seq'::regclass) | |
source_send_time | timestamp with time zone | ||
dest_recv_time | timestamp with time zone | ||
target_copy | bigint | NOT NULL | |
source | integer | NOT NULL | |
dest | integer | NOT NULL | |
prev_hop | integer | ||
copy_status | integer | NOT NULL | |
persistant_transfer | boolean | NOT NULL DEFAULT false | |
prev_dest | integer | ||
cancel_time | timestamp with time zone | ||
action.hold_request.id | hold | integer |
Table action.hold_transit_copy Inherits transit_copy,
active_hold_transit_cp_idx target_copy active_hold_transit_dest_idx dest active_hold_transit_source_idx source hold_transit_copy_hold_idx holdTable: action.in_house_use
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
item | bigint | NOT NULL | |
actor.usr.id | staff | integer | NOT NULL |
actor.workstation.id | workstation | integer | |
actor.org_unit.id | org_unit | integer | NOT NULL |
use_time | timestamp with time zone | NOT NULL DEFAULT now() |
Table: action.non_cat_in_house_use
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
config.non_cataloged_type.id | item_type | bigint | NOT NULL |
actor.usr.id | staff | integer | NOT NULL |
actor.workstation.id | workstation | integer | |
actor.org_unit.id | org_unit | integer | NOT NULL |
use_time | timestamp with time zone | NOT NULL DEFAULT now() |
Table: action.non_cataloged_circulation
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.usr.id | patron | integer | NOT NULL |
actor.usr.id | staff | integer | NOT NULL |
actor.org_unit.id | circ_lib | integer | NOT NULL |
config.non_cataloged_type.id | item_type | integer | NOT NULL |
circ_time | timestamp with time zone | NOT NULL DEFAULT now() |
View: action.open_circulation
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
usr | integer | ||
xact_start | timestamp with time zone | ||
xact_finish | timestamp with time zone | ||
unrecovered | boolean | ||
target_copy | bigint | ||
circ_lib | integer | ||
circ_staff | integer | ||
checkin_staff | integer | ||
checkin_lib | integer | ||
renewal_remaining | integer | ||
grace_period | interval | ||
due_date | timestamp with time zone | ||
stop_fines_time | timestamp with time zone | ||
checkin_time | timestamp with time zone | ||
create_time | timestamp with time zone | ||
duration | interval | ||
fine_interval | interval | ||
recurring_fine | numeric(6,2) | ||
max_fine | numeric(6,2) | ||
phone_renewal | boolean | ||
desk_renewal | boolean | ||
opac_renewal | boolean | ||
duration_rule | text | ||
recurring_fine_rule | text | ||
max_fine_rule | text | ||
stop_fines | text | ||
workstation | integer | ||
checkin_workstation | integer | ||
copy_location | integer | ||
checkin_scan_time | timestamp with time zone | ||
auto_renewal | boolean | ||
auto_renewal_remaining | integer | ||
parent_circ | bigint |
SELECT circulation.id , circulation.usr , circulation.xact_start , circulation.xact_finish , circulation.unrecovered , circulation.target_copy , circulation.circ_lib , circulation.circ_staff , circulation.checkin_staff , circulation.checkin_lib , circulation.renewal_remaining , circulation.grace_period , circulation.due_date , circulation.stop_fines_time , circulation.checkin_time , circulation.create_time , circulation.duration , circulation.fine_interval , circulation.recurring_fine , circulation.max_fine , circulation.phone_renewal , circulation.desk_renewal , circulation.opac_renewal , circulation.duration_rule , circulation.recurring_fine_rule , circulation.max_fine_rule , circulation.stop_fines , circulation.workstation , circulation.checkin_workstation , circulation.copy_location , circulation.checkin_scan_time , circulation.auto_renewal , circulation.auto_renewal_remaining , circulation.parent_circ FROM action.circulation WHERE (circulation.checkin_time IS NULL) ORDER BY circulation.due_date;
Table: action.reservation_transit_copy
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | PRIMARY KEY DEFAULT nextval('action.transit_copy_id_seq'::regclass) | |
source_send_time | timestamp with time zone | ||
dest_recv_time | timestamp with time zone | ||
booking.resource.id | target_copy | bigint | NOT NULL |
source | integer | NOT NULL | |
dest | integer | NOT NULL | |
prev_hop | integer | ||
copy_status | integer | NOT NULL | |
persistant_transfer | boolean | NOT NULL DEFAULT false | |
prev_dest | integer | ||
cancel_time | timestamp with time zone | ||
booking.reservation.id | reservation | integer |
Table action.reservation_transit_copy Inherits transit_copy,
active_reservation_transit_cp_idx target_copy active_reservation_transit_dest_idx dest active_reservation_transit_source_idx sourceTable: action.survey
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | owner | integer | NOT NULL |
start_date | timestamp with time zone | NOT NULL DEFAULT now() | |
end_date | timestamp with time zone | NOT NULL DEFAULT (now() + '10 years'::interval) | |
usr_summary | boolean | NOT NULL DEFAULT false | |
opac | boolean | NOT NULL DEFAULT false | |
poll | boolean | NOT NULL DEFAULT false | |
required | boolean | NOT NULL DEFAULT false | |
name | text | NOT NULL | |
description | text | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: action.survey_answer
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
action.survey_question.id | question | integer | NOT NULL |
answer | text | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: action.survey_question
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
action.survey.id | survey | integer | NOT NULL |
question | text | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: action.survey_response
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
response_group_id | integer | ||
usr | integer | ||
action.survey.id | survey | integer | NOT NULL |
action.survey_question.id | question | integer | NOT NULL |
action.survey_answer.id | answer | integer | NOT NULL |
answer_date | timestamp with time zone | ||
effective_date | timestamp with time zone | NOT NULL DEFAULT now() |
Table: action.transit_copy
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
source_send_time | timestamp with time zone | ||
dest_recv_time | timestamp with time zone | ||
target_copy | bigint | NOT NULL | |
actor.org_unit.id | source | integer | NOT NULL |
actor.org_unit.id | dest | integer | NOT NULL |
action.transit_copy.id | prev_hop | integer | |
config.copy_status.id | copy_status | integer | NOT NULL |
persistant_transfer | boolean | NOT NULL DEFAULT false | |
actor.org_unit.id | prev_dest | integer | |
cancel_time | timestamp with time zone |
Tables referencing this one via Foreign Key Constraints:
active_transit_cp_idx target_copy active_transit_dest_idx dest active_transit_for_copy target_copy) WHERE ((dest_recv_time IS NULL) AND (cancel_time IS NULL) active_transit_source_idx sourceView: action.unfulfilled_hold_innermost_loop
F-Key | Name | Type | Description |
---|---|---|---|
hold | integer | ||
circ_lib | integer | ||
count | bigint |
SELECT DISTINCT l.hold , l.circ_lib , l.count FROM (action.unfulfilled_hold_loops l JOIN action.unfulfilled_hold_min_loop m USING (hold) ) WHERE (l.count = m.min);
Table: action.unfulfilled_hold_list
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
current_copy | bigint | NOT NULL | |
hold | integer | NOT NULL | |
circ_lib | integer | NOT NULL | |
fail_time | timestamp with time zone | NOT NULL DEFAULT now() |
View: action.unfulfilled_hold_loops
F-Key | Name | Type | Description |
---|---|---|---|
hold | integer | ||
circ_lib | integer | ||
count | bigint |
SELECT u.hold , c.circ_lib , count (*) AS count FROM (action.unfulfilled_hold_list u JOIN asset.copy c ON ( (c.id = u.current_copy) ) ) GROUP BY u.hold , c.circ_lib;
View: action.unfulfilled_hold_max_loop
F-Key | Name | Type | Description |
---|---|---|---|
hold | integer | ||
max | bigint |
SELECT unfulfilled_hold_loops.hold , max (unfulfilled_hold_loops.count) AS max FROM action.unfulfilled_hold_loops GROUP BY unfulfilled_hold_loops.hold;
View: action.unfulfilled_hold_min_loop
F-Key | Name | Type | Description |
---|---|---|---|
hold | integer | ||
min | bigint |
SELECT unfulfilled_hold_loops.hold , min (unfulfilled_hold_loops.count) AS min FROM action.unfulfilled_hold_loops GROUP BY unfulfilled_hold_loops.hold;
Table: action.usr_circ_history
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
actor.usr.id | usr | integer | NOT NULL |
xact_start | timestamp with time zone | NOT NULL DEFAULT now() | |
target_copy | bigint | NOT NULL | |
due_date | timestamp with time zone | NOT NULL | |
checkin_time | timestamp with time zone | ||
action.circulation.id | source_circ | bigint |
Function: action.age_circ_on_delete()
Returns: trigger
Language: PLPGSQL
DECLARE found char := 'N'; BEGIN -- If there are any renewals for this circulation, don't archive or delete -- it yet. We'll do so later, when we archive and delete the renewals. SELECT 'Y' INTO found FROM action.circulation WHERE parent_circ = OLD.id LIMIT 1; IF found = 'Y' THEN RETURN NULL; -- don't delete END IF; -- Archive a copy of the old row to action.aged_circulation INSERT INTO action.aged_circulation (id,usr_post_code, usr_home_ou, usr_profile, usr_birth_year, copy_call_number, copy_location, copy_owning_lib, copy_circ_lib, copy_bib_record, xact_start, xact_finish, target_copy, circ_lib, circ_staff, checkin_staff, checkin_lib, renewal_remaining, grace_period, due_date, stop_fines_time, checkin_time, create_time, duration, fine_interval, recurring_fine, max_fine, phone_renewal, desk_renewal, opac_renewal, duration_rule, recurring_fine_rule, max_fine_rule, stop_fines, workstation, checkin_workstation, checkin_scan_time, parent_circ, auto_renewal, auto_renewal_remaining) SELECT id,usr_post_code, usr_home_ou, usr_profile, usr_birth_year, copy_call_number, copy_location, copy_owning_lib, copy_circ_lib, copy_bib_record, xact_start, xact_finish, target_copy, circ_lib, circ_staff, checkin_staff, checkin_lib, renewal_remaining, grace_period, due_date, stop_fines_time, checkin_time, create_time, duration, fine_interval, recurring_fine, max_fine, phone_renewal, desk_renewal, opac_renewal, duration_rule, recurring_fine_rule, max_fine_rule, stop_fines, workstation, checkin_workstation, checkin_scan_time, parent_circ, auto_renewal, auto_renewal_remaining FROM action.all_circulation WHERE id = OLD.id; -- Migrate billings and payments to aged tables SELECT 'Y' INTO found FROM config.global_flag WHERE name = 'history.money.age_with_circs' AND enabled; IF found = 'Y' THEN PERFORM money.age_billings_and_payments_for_xact(OLD.id); END IF; -- Break the link with the user in action_trigger.event (warning: event_output may essentially have this information) UPDATE action_trigger.event e SET context_user = NULL FROM action.all_circulation c WHERE c.id = OLD.id AND e.context_user = c.usr AND e.target = c.id AND e.event_def IN ( SELECT id FROM action_trigger.event_definition WHERE hook in (SELECT key FROM action_trigger.hook WHERE core_type = 'circ') ) ; RETURN OLD; END;
Function: action.age_hold_on_delete()
Returns: trigger
Language: PLPGSQL
DECLARE BEGIN -- Archive a copy of the old row to action.aged_hold_request INSERT INTO action.aged_hold_request (usr_post_code, usr_home_ou, usr_profile, usr_birth_year, staff_placed, id, request_time, capture_time, fulfillment_time, checkin_time, return_time, prev_check_time, expire_time, cancel_time, cancel_cause, cancel_note, target, current_copy, fulfillment_staff, fulfillment_lib, request_lib, selection_ou, selection_depth, pickup_lib, hold_type, holdable_formats, phone_notify, email_notify, sms_notify, frozen, thaw_date, shelf_time, cut_in_line, mint_condition, shelf_expire_time, current_shelf_lib, behind_desk) SELECT usr_post_code, usr_home_ou, usr_profile, usr_birth_year, staff_placed, id, request_time, capture_time, fulfillment_time, checkin_time, return_time, prev_check_time, expire_time, cancel_time, cancel_cause, cancel_note, target, current_copy, fulfillment_staff, fulfillment_lib, request_lib, selection_ou, selection_depth, pickup_lib, hold_type, holdable_formats, phone_notify, email_notify, sms_notify, frozen, thaw_date, shelf_time, cut_in_line, mint_condition, shelf_expire_time, current_shelf_lib, behind_desk FROM action.all_hold_request WHERE id = OLD.id; RETURN OLD; END;
Function: action.age_parent_circ_on_delete()
Returns: trigger
Language: PLPGSQL
BEGIN -- Having deleted a renewal, we can delete the original circulation (or a previous -- renewal, if that's what parent_circ is pointing to). That deletion will trigger -- deletion of any prior parents, etc. recursively. IF OLD.parent_circ IS NOT NULL THEN DELETE FROM action.circulation WHERE id = OLD.parent_circ; END IF; RETURN OLD; END;
Function: action.all_circ_chain(ctx_circ_id integer)
Returns: SET OF all_circulation_slim
Language: PLPGSQL
DECLARE tmp_circ action.all_circulation_slim%ROWTYPE; circ_0 action.all_circulation_slim%ROWTYPE; BEGIN SELECT INTO tmp_circ * FROM action.all_circulation_slim WHERE id = ctx_circ_id; IF tmp_circ IS NULL THEN RETURN NEXT tmp_circ; END IF; circ_0 := tmp_circ; -- find the front of the chain WHILE TRUE LOOP SELECT INTO tmp_circ * FROM action.all_circulation_slim WHERE id = tmp_circ.parent_circ; IF tmp_circ IS NULL THEN EXIT; END IF; circ_0 := tmp_circ; END LOOP; -- now send the circs to the caller, oldest to newest tmp_circ := circ_0; WHILE TRUE LOOP IF tmp_circ IS NULL THEN EXIT; END IF; RETURN NEXT tmp_circ; SELECT INTO tmp_circ * FROM action.all_circulation_slim WHERE parent_circ = tmp_circ.id; END LOOP; END;
Function: action.apply_fieldset(query integer, pkey_name text, table_name text, fieldset_id text)
Returns: text
Language: PLPGSQL
Applies a specified fieldset, using a supplied table name and primary key name. The query parameter should be non-null only for query-based fieldsets. Returns NULL if successful, or an error message if not.
DECLARE statement TEXT; where_clause TEXT; fs_status TEXT; fs_pkey_value TEXT; fs_query TEXT; sep CHAR; status_code TEXT; msg TEXT; fs_id INT; fsg_id INT; update_count INT; cv RECORD; fs_obj action.fieldset%ROWTYPE; fs_group action.fieldset_group%ROWTYPE; rb_row RECORD; BEGIN -- Sanity checks IF fieldset_id IS NULL THEN RETURN 'Fieldset ID parameter is NULL'; END IF; IF table_name IS NULL THEN RETURN 'Table name parameter is NULL'; END IF; IF pkey_name IS NULL THEN RETURN 'Primary key name parameter is NULL'; END IF; SELECT status, quote_literal( pkey_value ) INTO fs_status, fs_pkey_value FROM action.fieldset WHERE id = fieldset_id; -- -- Build the WHERE clause. This differs according to whether it's a -- single-row fieldset or a query-based fieldset. -- IF query IS NULL AND fs_pkey_value IS NULL THEN RETURN 'Incomplete fieldset: neither a primary key nor a query available'; ELSIF query IS NOT NULL AND fs_pkey_value IS NULL THEN fs_query := rtrim( query, ';' ); where_clause := 'WHERE ' || pkey_name || ' IN ( ' || fs_query || ' )'; ELSIF query IS NULL AND fs_pkey_value IS NOT NULL THEN where_clause := 'WHERE ' || pkey_name || ' = '; IF pkey_name = 'id' THEN where_clause := where_clause || fs_pkey_value; ELSIF pkey_name = 'code' THEN where_clause := where_clause || quote_literal(fs_pkey_value); ELSE RETURN 'Only know how to handle "id" and "code" pkeys currently, received ' || pkey_name; END IF; ELSE -- both are not null RETURN 'Ambiguous fieldset: both a primary key and a query provided'; END IF; IF fs_status IS NULL THEN RETURN 'No fieldset found for id = ' || fieldset_id; ELSIF fs_status = 'APPLIED' THEN RETURN 'Fieldset ' || fieldset_id || ' has already been applied'; END IF; SELECT * INTO fs_obj FROM action.fieldset WHERE id = fieldset_id; SELECT * INTO fs_group FROM action.fieldset_group WHERE id = fs_obj.fieldset_group; IF fs_group.can_rollback THEN -- This is part of a non-rollback group. We need to record the current values for future rollback. INSERT INTO action.fieldset_group (can_rollback, name, creator, owning_lib, container, container_type) VALUES (FALSE, 'ROLLBACK: '|| fs_group.name, fs_group.creator, fs_group.owning_lib, fs_group.container, fs_group.container_type); fsg_id := CURRVAL('action.fieldset_group_id_seq'); FOR rb_row IN EXECUTE 'SELECT * FROM ' || table_name || ' ' || where_clause LOOP IF pkey_name = 'id' THEN fs_pkey_value := rb_row.id; ELSIF pkey_name = 'code' THEN fs_pkey_value := rb_row.code; ELSE RETURN 'Only know how to handle "id" and "code" pkeys currently, received ' || pkey_name; END IF; INSERT INTO action.fieldset (fieldset_group,owner,owning_lib,status,classname,name,pkey_value) VALUES (fsg_id, fs_obj.owner, fs_obj.owning_lib, 'PENDING', fs_obj.classname, fs_obj.name || ' ROLLBACK FOR ' || fs_pkey_value, fs_pkey_value); fs_id := CURRVAL('action.fieldset_id_seq'); sep := ''; FOR cv IN SELECT DISTINCT col FROM action.fieldset_col_val WHERE fieldset = fieldset_id LOOP EXECUTE 'INSERT INTO action.fieldset_col_val (fieldset, col, val) ' || 'SELECT '|| fs_id || ', '||quote_literal(cv.col)||', '||cv.col||' FROM '||table_name||' WHERE '||pkey_name||' = '||fs_pkey_value; END LOOP; END LOOP; END IF; statement := 'UPDATE ' || table_name || ' SET'; sep := ''; FOR cv IN SELECT col, val FROM action.fieldset_col_val WHERE fieldset = fieldset_id LOOP statement := statement || sep || ' ' || cv.col || ' = ' || coalesce( quote_literal( cv.val ), 'NULL' ); sep := ','; END LOOP; IF sep = '' THEN RETURN 'Fieldset ' || fieldset_id || ' has no column values defined'; END IF; statement := statement || ' ' || where_clause; -- -- Execute the update -- BEGIN EXECUTE statement; GET DIAGNOSTICS update_count = ROW_COUNT; IF update_count = 0 THEN RAISE data_exception; END IF; IF fsg_id IS NOT NULL THEN UPDATE action.fieldset_group SET rollback_group = fsg_id WHERE id = fs_group.id; END IF; IF fs_group.id IS NOT NULL THEN UPDATE action.fieldset_group SET complete_time = now() WHERE id = fs_group.id; END IF; UPDATE action.fieldset SET status = 'APPLIED', applied_time = now() WHERE id = fieldset_id; EXCEPTION WHEN data_exception THEN msg := 'No eligible rows found for fieldset ' || fieldset_id; UPDATE action.fieldset SET status = 'ERROR', applied_time = now() WHERE id = fieldset_id; RETURN msg; END; RETURN msg; EXCEPTION WHEN OTHERS THEN msg := 'Unable to apply fieldset ' || fieldset_id || ': ' || sqlerrm; UPDATE action.fieldset SET status = 'ERROR', applied_time = now() WHERE id = fieldset_id; RETURN msg; END;
Function: action.archive_stat_cats()
Returns: trigger
Language: PLPGSQL
BEGIN INSERT INTO action.archive_actor_stat_cat(xact, stat_cat, value) SELECT NEW.id, asceum.stat_cat, asceum.stat_cat_entry FROM actor.stat_cat_entry_usr_map asceum JOIN actor.stat_cat sc ON asceum.stat_cat = sc.id WHERE NEW.usr = asceum.target_usr AND sc.checkout_archive; INSERT INTO action.archive_asset_stat_cat(xact, stat_cat, value) SELECT NEW.id, ascecm.stat_cat, asce.value FROM asset.stat_cat_entry_copy_map ascecm JOIN asset.stat_cat sc ON ascecm.stat_cat = sc.id JOIN asset.stat_cat_entry asce ON ascecm.stat_cat_entry = asce.id WHERE NEW.target_copy = ascecm.owning_copy AND sc.checkout_archive; RETURN NULL; END;
Function: action.circ_chain(ctx_circ_id bigint)
Returns: SET OF circulation
Language: PLPGSQL
DECLARE tmp_circ action.circulation%ROWTYPE; circ_0 action.circulation%ROWTYPE; BEGIN SELECT INTO tmp_circ * FROM action.circulation WHERE id = ctx_circ_id; IF tmp_circ IS NULL THEN RETURN NEXT tmp_circ; END IF; circ_0 := tmp_circ; -- find the front of the chain WHILE TRUE LOOP SELECT INTO tmp_circ * FROM action.circulation WHERE id = tmp_circ.parent_circ; IF tmp_circ IS NULL THEN EXIT; END IF; circ_0 := tmp_circ; END LOOP; -- now send the circs to the caller, oldest to newest tmp_circ := circ_0; WHILE TRUE LOOP IF tmp_circ IS NULL THEN EXIT; END IF; RETURN NEXT tmp_circ; SELECT INTO tmp_circ * FROM action.circulation WHERE parent_circ = tmp_circ.id; END LOOP; END;
Function: action.circulation_claims_returned()
Returns: trigger
Language: PLPGSQL
BEGIN IF OLD.stop_fines IS NULL OR OLD.stop_fines <> NEW.stop_fines THEN IF NEW.stop_fines = 'CLAIMSRETURNED' THEN UPDATE actor.usr SET claims_returned_count = claims_returned_count + 1 WHERE id = NEW.usr; END IF; IF NEW.stop_fines = 'CLAIMSNEVERCHECKEDOUT' THEN UPDATE actor.usr SET claims_never_checked_out_count = claims_never_checked_out_count + 1 WHERE id = NEW.usr; END IF; IF NEW.stop_fines = 'LOST' THEN UPDATE asset.copy SET status = 3 WHERE id = NEW.target_copy; END IF; END IF; RETURN NEW; END;
Function: action.copy_calculated_proximity(vacl_ol integer, vacn_ol integer, vacp_cm integer, vacp_cl text, request integer, pickup integer)
Returns: numeric
Language: PLPGSQL
DECLARE baseline_prox NUMERIC; aoupa actor.org_unit_proximity_adjustment%ROWTYPE; BEGIN -- First, gather the baseline proximity of "here" to pickup lib SELECT prox INTO baseline_prox FROM actor.org_unit_proximity WHERE from_org = vacp_cl AND to_org = pickup; -- Find any absolute adjustments, and set the baseline prox to that SELECT adj.* INTO aoupa FROM actor.org_unit_proximity_adjustment adj LEFT JOIN actor.org_unit_ancestors_distance(vacp_cl) acp_cl ON (acp_cl.id = adj.item_circ_lib) LEFT JOIN actor.org_unit_ancestors_distance(vacn_ol) acn_ol ON (acn_ol.id = adj.item_owning_lib) LEFT JOIN actor.org_unit_ancestors_distance(vacl_ol) acl_ol ON (acl_ol.id = adj.copy_location) LEFT JOIN actor.org_unit_ancestors_distance(pickup) ahr_pl ON (ahr_pl.id = adj.hold_pickup_lib) LEFT JOIN actor.org_unit_ancestors_distance(request) ahr_rl ON (ahr_rl.id = adj.hold_request_lib) WHERE (adj.circ_mod IS NULL OR adj.circ_mod = vacp_cm) AND (adj.item_circ_lib IS NULL OR adj.item_circ_lib = acp_cl.id) AND (adj.item_owning_lib IS NULL OR adj.item_owning_lib = acn_ol.id) AND (adj.copy_location IS NULL OR adj.copy_location = acl_ol.id) AND (adj.hold_pickup_lib IS NULL OR adj.hold_pickup_lib = ahr_pl.id) AND (adj.hold_request_lib IS NULL OR adj.hold_request_lib = ahr_rl.id) AND absolute_adjustment AND COALESCE(acp_cl.id, acn_ol.id, acl_ol.id, ahr_pl.id, ahr_rl.id) IS NOT NULL ORDER BY COALESCE(acp_cl.distance,999) + COALESCE(acn_ol.distance,999) + COALESCE(acl_ol.distance,999) + COALESCE(ahr_pl.distance,999) + COALESCE(ahr_rl.distance,999), adj.pos LIMIT 1; IF FOUND THEN baseline_prox := aoupa.prox_adjustment; END IF; -- Now find any relative adjustments, and change the baseline prox based on them FOR aoupa IN SELECT adj.* FROM actor.org_unit_proximity_adjustment adj LEFT JOIN actor.org_unit_ancestors_distance(vacp_cl) acp_cl ON (acp_cl.id = adj.item_circ_lib) LEFT JOIN actor.org_unit_ancestors_distance(vacn_ol) acn_ol ON (acn_ol.id = adj.item_owning_lib) LEFT JOIN actor.org_unit_ancestors_distance(vacl_ol) acl_ol ON (acn_ol.id = adj.copy_location) LEFT JOIN actor.org_unit_ancestors_distance(pickup) ahr_pl ON (ahr_pl.id = adj.hold_pickup_lib) LEFT JOIN actor.org_unit_ancestors_distance(request) ahr_rl ON (ahr_rl.id = adj.hold_request_lib) WHERE (adj.circ_mod IS NULL OR adj.circ_mod = vacp_cm) AND (adj.item_circ_lib IS NULL OR adj.item_circ_lib = acp_cl.id) AND (adj.item_owning_lib IS NULL OR adj.item_owning_lib = acn_ol.id) AND (adj.copy_location IS NULL OR adj.copy_location = acl_ol.id) AND (adj.hold_pickup_lib IS NULL OR adj.hold_pickup_lib = ahr_pl.id) AND (adj.hold_request_lib IS NULL OR adj.hold_request_lib = ahr_rl.id) AND NOT absolute_adjustment AND COALESCE(acp_cl.id, acn_ol.id, acl_ol.id, ahr_pl.id, ahr_rl.id) IS NOT NULL LOOP baseline_prox := baseline_prox + aoupa.prox_adjustment; END LOOP; RETURN baseline_prox; END;
Function: action.copy_related_hold_stats(copy_id bigint)
Returns: hold_stats
Language: PLPGSQL
DECLARE output action.hold_stats%ROWTYPE; hold_count INT := 0; copy_count INT := 0; available_count INT := 0; hold_map_data RECORD; BEGIN output.hold_count := 0; output.copy_count := 0; output.available_count := 0; SELECT COUNT( DISTINCT m.hold ) INTO hold_count FROM action.hold_copy_map m JOIN action.hold_request h ON (m.hold = h.id) WHERE m.target_copy = copy_id AND NOT h.frozen; output.hold_count := hold_count; IF output.hold_count > 0 THEN FOR hold_map_data IN SELECT DISTINCT m.target_copy, acp.status FROM action.hold_copy_map m JOIN asset.copy acp ON (m.target_copy = acp.id) JOIN action.hold_request h ON (m.hold = h.id) WHERE m.hold IN ( SELECT DISTINCT hold FROM action.hold_copy_map WHERE target_copy = copy_id ) AND NOT h.frozen LOOP output.copy_count := output.copy_count + 1; IF hold_map_data.status IN (0,7,12) THEN output.available_count := output.available_count + 1; END IF; END LOOP; output.total_copy_ratio = output.copy_count::FLOAT / output.hold_count::FLOAT; output.available_copy_ratio = output.available_count::FLOAT / output.hold_count::FLOAT; END IF; RETURN output; END;
Function: action.copy_transit_is_unique()
Returns: trigger
Language: PLPGSQL
BEGIN PERFORM * FROM action.transit_copy WHERE target_copy = NEW.target_copy AND dest_recv_time IS NULL AND cancel_time IS NULL; IF FOUND THEN RAISE EXCEPTION 'Copy id=% is already in transit', NEW.target_copy; END IF; RETURN NULL; END;
Function: action.emergency_closing_stage_1(e_closing integer)
Returns: SET OF emergency_closing_stage_1_count
Language: PLPGSQL
DECLARE tmp INT; touched action.emergency_closing_stage_1_count%ROWTYPE; BEGIN -- First, gather circs INSERT INTO action.emergency_closing_circulation (emergency_closing, circulation) SELECT e_closing, circ.id FROM actor.org_unit_closed closing JOIN action.emergency_closing ec ON (closing.emergency_closing = ec.id AND ec.id = e_closing) JOIN action.circulation circ ON ( circ.circ_lib = closing.org_unit AND circ.due_date BETWEEN closing.close_start AND (closing.close_end + '1s'::INTERVAL) AND circ.xact_finish IS NULL ) WHERE NOT EXISTS (SELECT 1 FROM action.emergency_closing_circulation t WHERE t.emergency_closing = e_closing AND t.circulation = circ.id); GET DIAGNOSTICS tmp = ROW_COUNT; touched.circulations := tmp; INSERT INTO action.emergency_closing_reservation (emergency_closing, reservation) SELECT e_closing, res.id FROM actor.org_unit_closed closing JOIN action.emergency_closing ec ON (closing.emergency_closing = ec.id AND ec.id = e_closing) JOIN booking.reservation res ON ( res.pickup_lib = closing.org_unit AND res.end_time BETWEEN closing.close_start AND (closing.close_end + '1s'::INTERVAL) ) WHERE NOT EXISTS (SELECT 1 FROM action.emergency_closing_reservation t WHERE t.emergency_closing = e_closing AND t.reservation = res.id); GET DIAGNOSTICS tmp = ROW_COUNT; touched.reservations := tmp; INSERT INTO action.emergency_closing_hold (emergency_closing, hold) SELECT e_closing, hold.id FROM actor.org_unit_closed closing JOIN action.emergency_closing ec ON (closing.emergency_closing = ec.id AND ec.id = e_closing) JOIN action.hold_request hold ON ( pickup_lib = closing.org_unit AND hold.shelf_expire_time BETWEEN closing.close_start AND (closing.close_end + '1s'::INTERVAL) AND hold.fulfillment_time IS NULL AND hold.cancel_time IS NULL ) WHERE NOT EXISTS (SELECT 1 FROM action.emergency_closing_hold t WHERE t.emergency_closing = e_closing AND t.hold = hold.id); GET DIAGNOSTICS tmp = ROW_COUNT; touched.holds := tmp; UPDATE action.emergency_closing SET process_start_time = NOW(), last_update_time = NOW() WHERE id = e_closing; RETURN NEXT touched; END;
Function: action.emergency_closing_stage_2_circ(circ_closing_entry integer)
Returns: boolean
Language: PLPGSQL
DECLARE circ action.circulation%ROWTYPE; e_closing action.emergency_closing%ROWTYPE; e_c_circ action.emergency_closing_circulation%ROWTYPE; closing actor.org_unit_closed%ROWTYPE; adjacent actor.org_unit_closed%ROWTYPE; bill money.billing%ROWTYPE; last_bill money.billing%ROWTYPE; day_number INT; hoo_close TIME WITHOUT TIME ZONE; plus_days INT; avoid_negative BOOL; extend_grace BOOL; new_due_date TEXT; BEGIN -- Gather objects involved SELECT * INTO e_c_circ FROM action.emergency_closing_circulation WHERE id = circ_closing_entry; IF e_c_circ.process_time IS NOT NULL THEN -- Already processed ... moving on RETURN FALSE; END IF; SELECT * INTO e_closing FROM action.emergency_closing WHERE id = e_c_circ.emergency_closing; IF e_closing.process_start_time IS NULL THEN -- Huh... that's odd. And wrong. RETURN FALSE; END IF; SELECT * INTO closing FROM actor.org_unit_closed WHERE emergency_closing = e_closing.id; SELECT * INTO circ FROM action.circulation WHERE id = e_c_circ.circulation; -- Record the processing UPDATE action.emergency_closing_circulation SET original_due_date = circ.due_date, process_time = NOW() WHERE id = circ_closing_entry; UPDATE action.emergency_closing SET last_update_time = NOW() WHERE id = e_closing.id; SELECT value::BOOL INTO avoid_negative FROM actor.org_unit_ancestor_setting('bill.prohibit_negative_balance_on_overdues', circ.circ_lib); SELECT value::BOOL INTO extend_grace FROM actor.org_unit_ancestor_setting('circ.grace.extend', circ.circ_lib); new_due_date := evergreen.find_next_open_time( closing.org_unit, circ.due_date, EXTRACT(EPOCH FROM circ.duration)::INT % 86400 > 0 )::TEXT; UPDATE action.circulation SET due_date = new_due_date::TIMESTAMPTZ WHERE id = circ.id; -- Now, see if we need to get rid of some fines SELECT * INTO last_bill FROM money.billing b WHERE b.xact = circ.id AND NOT b.voided AND b.btype = 1 ORDER BY billing_ts DESC LIMIT 1; FOR bill IN SELECT * FROM money.billing b WHERE b.xact = circ.id AND b.btype = 1 AND NOT b.voided AND ( b.billing_ts BETWEEN closing.close_start AND new_due_date::TIMESTAMPTZ OR (extend_grace AND last_bill.billing_ts <= new_due_date::TIMESTAMPTZ + circ.grace_period) ) AND NOT EXISTS (SELECT 1 FROM money.account_adjustment a WHERE a.billing = b.id) ORDER BY billing_ts LOOP IF avoid_negative THEN PERFORM FROM money.materialized_billable_xact_summary WHERE id = circ.id AND balance_owed < bill.amount; EXIT WHEN FOUND; -- We can't go negative, and voiding this bill would do that... END IF; UPDATE money.billing SET voided = TRUE, void_time = NOW(), note = COALESCE(note,'') || ' :: Voided by emergency closing handler' WHERE id = bill.id; END LOOP; RETURN TRUE; END;
Function: action.emergency_closing_stage_2_hold(hold_closing_entry integer)
Returns: boolean
Language: PLPGSQL
DECLARE hold action.hold_request%ROWTYPE; e_closing action.emergency_closing%ROWTYPE; e_c_hold action.emergency_closing_hold%ROWTYPE; closing actor.org_unit_closed%ROWTYPE; day_number INT; hoo_close TIME WITHOUT TIME ZONE; plus_days INT; BEGIN -- Gather objects involved SELECT * INTO e_c_hold FROM action.emergency_closing_hold WHERE id = hold_closing_entry; IF e_c_hold.process_time IS NOT NULL THEN -- Already processed ... moving on RETURN FALSE; END IF; SELECT * INTO e_closing FROM action.emergency_closing WHERE id = e_c_hold.emergency_closing; IF e_closing.process_start_time IS NULL THEN -- Huh... that's odd. And wrong. RETURN FALSE; END IF; SELECT * INTO closing FROM actor.org_unit_closed WHERE emergency_closing = e_closing.id; SELECT * INTO hold FROM action.hold_request h WHERE id = e_c_hold.hold; -- Record the processing UPDATE action.emergency_closing_hold SET original_shelf_expire_time = hold.shelf_expire_time, process_time = NOW() WHERE id = hold_closing_entry; UPDATE action.emergency_closing SET last_update_time = NOW() WHERE id = e_closing.id; UPDATE action.hold_request SET shelf_expire_time = evergreen.find_next_open_time(closing.org_unit, hold.shelf_expire_time, TRUE) WHERE id = hold.id; RETURN TRUE; END;
Function: action.emergency_closing_stage_2_reservation(res_closing_entry integer)
Returns: boolean
Language: PLPGSQL
DECLARE res booking.reservation%ROWTYPE; e_closing action.emergency_closing%ROWTYPE; e_c_res action.emergency_closing_reservation%ROWTYPE; closing actor.org_unit_closed%ROWTYPE; adjacent actor.org_unit_closed%ROWTYPE; bill money.billing%ROWTYPE; day_number INT; hoo_close TIME WITHOUT TIME ZONE; plus_days INT; avoid_negative BOOL; new_due_date TEXT; BEGIN -- Gather objects involved SELECT * INTO e_c_res FROM action.emergency_closing_reservation WHERE id = res_closing_entry; IF e_c_res.process_time IS NOT NULL THEN -- Already processed ... moving on RETURN FALSE; END IF; SELECT * INTO e_closing FROM action.emergency_closing WHERE id = e_c_res.emergency_closing; IF e_closing.process_start_time IS NULL THEN -- Huh... that's odd. And wrong. RETURN FALSE; END IF; SELECT * INTO closing FROM actor.org_unit_closed WHERE emergency_closing = e_closing.id; SELECT * INTO res FROM booking.reservation WHERE id = e_c_res.reservation; IF res.pickup_lib IS NULL THEN -- Need to be far enough along to have a pickup lib RETURN FALSE; END IF; -- Record the processing UPDATE action.emergency_closing_reservation SET original_end_time = res.end_time, process_time = NOW() WHERE id = res_closing_entry; UPDATE action.emergency_closing SET last_update_time = NOW() WHERE id = e_closing.id; SELECT value::BOOL INTO avoid_negative FROM actor.org_unit_ancestor_setting('bill.prohibit_negative_balance_on_overdues', res.pickup_lib); new_due_date := evergreen.find_next_open_time( closing.org_unit, res.end_time, EXTRACT(EPOCH FROM res.booking_interval)::INT % 86400 > 0 )::TEXT; UPDATE booking.reservation SET end_time = new_due_date::TIMESTAMPTZ WHERE id = res.id; -- Now, see if we need to get rid of some fines FOR bill IN SELECT * FROM money.billing b WHERE b.xact = res.id AND b.btype = 1 AND NOT b.voided AND b.billing_ts BETWEEN closing.close_start AND new_due_date::TIMESTAMPTZ AND NOT EXISTS (SELECT 1 FROM money.account_adjustment a WHERE a.billing = b.id) LOOP IF avoid_negative THEN PERFORM FROM money.materialized_billable_xact_summary WHERE id = res.id AND balance_owed < bill.amount; EXIT WHEN FOUND; -- We can't go negative, and voiding this bill would do that... END IF; UPDATE money.billing SET voided = TRUE, void_time = NOW(), note = COALESCE(note,'') || ' :: Voided by emergency closing handler' WHERE id = bill.id; END LOOP; RETURN TRUE; END;
Function: action.fill_circ_copy_location()
Returns: trigger
Language: PLPGSQL
BEGIN SELECT INTO NEW.copy_location location FROM asset.copy WHERE id = NEW.target_copy; RETURN NEW; END;
Function: action.find_circ_matrix_matchpoint(renewal integer, match_user bigint, match_item integer, context_ou boolean)
Returns: SET OF found_circ_matrix_matchpoint
Language: PLPGSQL
DECLARE item_object asset.copy%ROWTYPE; user_object actor.usr%ROWTYPE; BEGIN SELECT INTO item_object * FROM asset.copy WHERE id = match_item; SELECT INTO user_object * FROM actor.usr WHERE id = match_user; RETURN QUERY SELECT * FROM action.find_circ_matrix_matchpoint( context_ou, item_object, user_object, renewal ); END;
Function: action.find_circ_matrix_matchpoint(renewal integer, user_object asset.copy, item_object actor.usr, context_ou boolean)
Returns: found_circ_matrix_matchpoint
Language: PLPGSQL
DECLARE cn_object asset.call_number%ROWTYPE; rec_descriptor metabib.rec_descriptor%ROWTYPE; cur_matchpoint config.circ_matrix_matchpoint%ROWTYPE; matchpoint config.circ_matrix_matchpoint%ROWTYPE; weights config.circ_matrix_weights%ROWTYPE; user_age INTERVAL; my_item_age INTERVAL; denominator NUMERIC(6,2); row_list INT[]; result action.found_circ_matrix_matchpoint; BEGIN -- Assume failure result.success = false; -- Fetch useful data SELECT INTO cn_object * FROM asset.call_number WHERE id = item_object.call_number; SELECT INTO rec_descriptor * FROM metabib.rec_descriptor WHERE record = cn_object.record; -- Pre-generate this so we only calc it once IF user_object.dob IS NOT NULL THEN SELECT INTO user_age age(user_object.dob); END IF; -- Ditto SELECT INTO my_item_age age(coalesce(item_object.active_date, now())); -- Grab the closest set circ weight setting. SELECT INTO weights cw.* FROM config.weight_assoc wa JOIN config.circ_matrix_weights cw ON (cw.id = wa.circ_weights) JOIN actor.org_unit_ancestors_distance( context_ou ) d ON (wa.org_unit = d.id) WHERE active ORDER BY d.distance LIMIT 1; -- No weights? Bad admin! Defaults to handle that anyway. IF weights.id IS NULL THEN weights.grp := 11.0; weights.org_unit := 10.0; weights.circ_modifier := 5.0; weights.copy_location := 5.0; weights.marc_type := 4.0; weights.marc_form := 3.0; weights.marc_bib_level := 2.0; weights.marc_vr_format := 2.0; weights.copy_circ_lib := 8.0; weights.copy_owning_lib := 8.0; weights.user_home_ou := 8.0; weights.ref_flag := 1.0; weights.juvenile_flag := 6.0; weights.is_renewal := 7.0; weights.usr_age_lower_bound := 0.0; weights.usr_age_upper_bound := 0.0; weights.item_age := 0.0; END IF; -- Determine the max (expected) depth (+1) of the org tree and max depth of the permisson tree -- If you break your org tree with funky parenting this may be wrong -- Note: This CTE is duplicated in the find_hold_matrix_matchpoint function, and it may be a good idea to split it off to a function -- We use one denominator for all tree-based checks for when permission groups and org units have the same weighting WITH all_distance(distance) AS ( SELECT depth AS distance FROM actor.org_unit_type UNION SELECT distance AS distance FROM permission.grp_ancestors_distance((SELECT id FROM permission.grp_tree WHERE parent IS NULL)) ) SELECT INTO denominator MAX(distance) + 1 FROM all_distance; -- Loop over all the potential matchpoints FOR cur_matchpoint IN SELECT m.* FROM config.circ_matrix_matchpoint m /*LEFT*/ JOIN permission.grp_ancestors_distance( user_object.profile ) upgad ON m.grp = upgad.id /*LEFT*/ JOIN actor.org_unit_ancestors_distance( context_ou ) ctoua ON m.org_unit = ctoua.id LEFT JOIN actor.org_unit_ancestors_distance( cn_object.owning_lib ) cnoua ON m.copy_owning_lib = cnoua.id LEFT JOIN actor.org_unit_ancestors_distance( item_object.circ_lib ) iooua ON m.copy_circ_lib = iooua.id LEFT JOIN actor.org_unit_ancestors_distance( user_object.home_ou ) uhoua ON m.user_home_ou = uhoua.id WHERE m.active -- Permission Groups -- AND (m.grp IS NULL OR upgad.id IS NOT NULL) -- Optional Permission Group? -- Org Units -- AND (m.org_unit IS NULL OR ctoua.id IS NOT NULL) -- Optional Org Unit? AND (m.copy_owning_lib IS NULL OR cnoua.id IS NOT NULL) AND (m.copy_circ_lib IS NULL OR iooua.id IS NOT NULL) AND (m.user_home_ou IS NULL OR uhoua.id IS NOT NULL) -- Circ Type AND (m.is_renewal IS NULL OR m.is_renewal = renewal) -- Static User Checks AND (m.juvenile_flag IS NULL OR m.juvenile_flag = user_object.juvenile) AND (m.usr_age_lower_bound IS NULL OR (user_age IS NOT NULL AND m.usr_age_lower_bound < user_age)) AND (m.usr_age_upper_bound IS NULL OR (user_age IS NOT NULL AND m.usr_age_upper_bound > user_age)) -- Static Item Checks AND (m.circ_modifier IS NULL OR m.circ_modifier = item_object.circ_modifier) AND (m.copy_location IS NULL OR m.copy_location = item_object.location) AND (m.marc_type IS NULL OR m.marc_type = COALESCE(item_object.circ_as_type, rec_descriptor.item_type)) AND (m.marc_form IS NULL OR m.marc_form = rec_descriptor.item_form) AND (m.marc_bib_level IS NULL OR m.marc_bib_level = rec_descriptor.bib_level) AND (m.marc_vr_format IS NULL OR m.marc_vr_format = rec_descriptor.vr_format) AND (m.ref_flag IS NULL OR m.ref_flag = item_object.ref) AND (m.item_age IS NULL OR (my_item_age IS NOT NULL AND m.item_age > my_item_age)) ORDER BY -- Permission Groups CASE WHEN upgad.distance IS NOT NULL THEN 2^(2*weights.grp - (upgad.distance/denominator)) ELSE 0.0 END + -- Org Units CASE WHEN ctoua.distance IS NOT NULL THEN 2^(2*weights.org_unit - (ctoua.distance/denominator)) ELSE 0.0 END + CASE WHEN cnoua.distance IS NOT NULL THEN 2^(2*weights.copy_owning_lib - (cnoua.distance/denominator)) ELSE 0.0 END + CASE WHEN iooua.distance IS NOT NULL THEN 2^(2*weights.copy_circ_lib - (iooua.distance/denominator)) ELSE 0.0 END + CASE WHEN uhoua.distance IS NOT NULL THEN 2^(2*weights.user_home_ou - (uhoua.distance/denominator)) ELSE 0.0 END + -- Circ Type -- Note: 4^x is equiv to 2^(2*x) CASE WHEN m.is_renewal IS NOT NULL THEN 4^weights.is_renewal ELSE 0.0 END + -- Static User Checks CASE WHEN m.juvenile_flag IS NOT NULL THEN 4^weights.juvenile_flag ELSE 0.0 END + CASE WHEN m.usr_age_lower_bound IS NOT NULL THEN 4^weights.usr_age_lower_bound ELSE 0.0 END + CASE WHEN m.usr_age_upper_bound IS NOT NULL THEN 4^weights.usr_age_upper_bound ELSE 0.0 END + -- Static Item Checks CASE WHEN m.circ_modifier IS NOT NULL THEN 4^weights.circ_modifier ELSE 0.0 END + CASE WHEN m.copy_location IS NOT NULL THEN 4^weights.copy_location ELSE 0.0 END + CASE WHEN m.marc_type IS NOT NULL THEN 4^weights.marc_type ELSE 0.0 END + CASE WHEN m.marc_form IS NOT NULL THEN 4^weights.marc_form ELSE 0.0 END + CASE WHEN m.marc_vr_format IS NOT NULL THEN 4^weights.marc_vr_format ELSE 0.0 END + CASE WHEN m.ref_flag IS NOT NULL THEN 4^weights.ref_flag ELSE 0.0 END + -- Item age has a slight adjustment to weight based on value. -- This should ensure that a shorter age limit comes first when all else is equal. -- NOTE: This assumes that intervals will normally be in days. CASE WHEN m.item_age IS NOT NULL THEN 4^weights.item_age - 1 + 86400/EXTRACT(EPOCH FROM m.item_age) ELSE 0.0 END DESC, -- Final sort on id, so that if two rules have the same sorting in the previous sort they have a defined order -- This prevents "we changed the table order by updating a rule, and we started getting different results" m.id LOOP -- Record the full matching row list row_list := row_list || cur_matchpoint.id; -- No matchpoint yet? IF matchpoint.id IS NULL THEN -- Take the entire matchpoint as a starting point matchpoint := cur_matchpoint; CONTINUE; -- No need to look at this row any more. END IF; -- Incomplete matchpoint? IF matchpoint.circulate IS NULL THEN matchpoint.circulate := cur_matchpoint.circulate; END IF; IF matchpoint.duration_rule IS NULL THEN matchpoint.duration_rule := cur_matchpoint.duration_rule; END IF; IF matchpoint.recurring_fine_rule IS NULL THEN matchpoint.recurring_fine_rule := cur_matchpoint.recurring_fine_rule; END IF; IF matchpoint.max_fine_rule IS NULL THEN matchpoint.max_fine_rule := cur_matchpoint.max_fine_rule; END IF; IF matchpoint.hard_due_date IS NULL THEN matchpoint.hard_due_date := cur_matchpoint.hard_due_date; END IF; IF matchpoint.total_copy_hold_ratio IS NULL THEN matchpoint.total_copy_hold_ratio := cur_matchpoint.total_copy_hold_ratio; END IF; IF matchpoint.available_copy_hold_ratio IS NULL THEN matchpoint.available_copy_hold_ratio := cur_matchpoint.available_copy_hold_ratio; END IF; IF matchpoint.renewals IS NULL THEN matchpoint.renewals := cur_matchpoint.renewals; END IF; IF matchpoint.grace_period IS NULL THEN matchpoint.grace_period := cur_matchpoint.grace_period; END IF; END LOOP; -- Check required fields IF matchpoint.circulate IS NOT NULL AND matchpoint.duration_rule IS NOT NULL AND matchpoint.recurring_fine_rule IS NOT NULL AND matchpoint.max_fine_rule IS NOT NULL THEN -- All there? We have a completed match. result.success := true; END IF; -- Include the assembled matchpoint, even if it isn't complete result.matchpoint := matchpoint; -- Include (for debugging) the full list of matching rows result.buildrows := row_list; -- Hand the result back to caller RETURN result; END;
Function: action.find_hold_matrix_matchpoint(match_requestor integer, match_user integer, match_item bigint, request_ou integer, pickup_ou integer)
Returns: integer
Language: PLPGSQL
DECLARE requestor_object actor.usr%ROWTYPE; user_object actor.usr%ROWTYPE; item_object asset.copy%ROWTYPE; item_cn_object asset.call_number%ROWTYPE; my_item_age INTERVAL; rec_descriptor metabib.rec_descriptor%ROWTYPE; matchpoint config.hold_matrix_matchpoint%ROWTYPE; weights config.hold_matrix_weights%ROWTYPE; denominator NUMERIC(6,2); v_pickup_ou ALIAS FOR pickup_ou; v_request_ou ALIAS FOR request_ou; BEGIN SELECT INTO user_object * FROM actor.usr WHERE id = match_user; SELECT INTO requestor_object * FROM actor.usr WHERE id = match_requestor; SELECT INTO item_object * FROM asset.copy WHERE id = match_item; SELECT INTO item_cn_object * FROM asset.call_number WHERE id = item_object.call_number; SELECT INTO rec_descriptor * FROM metabib.rec_descriptor WHERE record = item_cn_object.record; SELECT INTO my_item_age age(coalesce(item_object.active_date, now())); -- The item's owner should probably be the one determining if the item is holdable -- How to decide that is debatable. Decided to default to the circ library (where the item lives) -- This flag will allow for setting it to the owning library (where the call number "lives") PERFORM * FROM config.internal_flag WHERE name = 'circ.holds.weight_owner_not_circ' AND enabled; -- Grab the closest set circ weight setting. IF NOT FOUND THEN -- Default to circ library SELECT INTO weights hw.* FROM config.weight_assoc wa JOIN config.hold_matrix_weights hw ON (hw.id = wa.hold_weights) JOIN actor.org_unit_ancestors_distance( item_object.circ_lib ) d ON (wa.org_unit = d.id) WHERE active ORDER BY d.distance LIMIT 1; ELSE -- Flag is set, use owning library SELECT INTO weights hw.* FROM config.weight_assoc wa JOIN config.hold_matrix_weights hw ON (hw.id = wa.hold_weights) JOIN actor.org_unit_ancestors_distance( item_cn_object.owning_lib ) d ON (wa.org_unit = d.id) WHERE active ORDER BY d.distance LIMIT 1; END IF; -- No weights? Bad admin! Defaults to handle that anyway. IF weights.id IS NULL THEN weights.user_home_ou := 5.0; weights.request_ou := 5.0; weights.pickup_ou := 5.0; weights.item_owning_ou := 5.0; weights.item_circ_ou := 5.0; weights.usr_grp := 7.0; weights.requestor_grp := 8.0; weights.circ_modifier := 4.0; weights.marc_type := 3.0; weights.marc_form := 2.0; weights.marc_bib_level := 1.0; weights.marc_vr_format := 1.0; weights.juvenile_flag := 4.0; weights.ref_flag := 0.0; weights.item_age := 0.0; END IF; -- Determine the max (expected) depth (+1) of the org tree and max depth of the permisson tree -- If you break your org tree with funky parenting this may be wrong -- Note: This CTE is duplicated in the find_circ_matrix_matchpoint function, and it may be a good idea to split it off to a function -- We use one denominator for all tree-based checks for when permission groups and org units have the same weighting WITH all_distance(distance) AS ( SELECT depth AS distance FROM actor.org_unit_type UNION SELECT distance AS distance FROM permission.grp_ancestors_distance((SELECT id FROM permission.grp_tree WHERE parent IS NULL)) ) SELECT INTO denominator MAX(distance) + 1 FROM all_distance; -- To ATTEMPT to make this work like it used to, make it reverse the user/requestor profile ids. -- This may be better implemented as part of the upgrade script? -- Set usr_grp = requestor_grp, requestor_grp = 1 or something when this flag is already set -- Then remove this flag, of course. PERFORM * FROM config.internal_flag WHERE name = 'circ.holds.usr_not_requestor' AND enabled; IF FOUND THEN -- Note: This, to me, is REALLY hacky. I put it in anyway. -- If you can't tell, this is a single call swap on two variables. SELECT INTO user_object.profile, requestor_object.profile requestor_object.profile, user_object.profile; END IF; -- Select the winning matchpoint into the matchpoint variable for returning SELECT INTO matchpoint m.* FROM config.hold_matrix_matchpoint m /*LEFT*/ JOIN permission.grp_ancestors_distance( requestor_object.profile ) rpgad ON m.requestor_grp = rpgad.id LEFT JOIN permission.grp_ancestors_distance( user_object.profile ) upgad ON m.usr_grp = upgad.id LEFT JOIN actor.org_unit_ancestors_distance( v_pickup_ou ) puoua ON m.pickup_ou = puoua.id LEFT JOIN actor.org_unit_ancestors_distance( v_request_ou ) rqoua ON m.request_ou = rqoua.id LEFT JOIN actor.org_unit_ancestors_distance( item_cn_object.owning_lib ) cnoua ON m.item_owning_ou = cnoua.id LEFT JOIN actor.org_unit_ancestors_distance( item_object.circ_lib ) iooua ON m.item_circ_ou = iooua.id LEFT JOIN actor.org_unit_ancestors_distance( user_object.home_ou ) uhoua ON m.user_home_ou = uhoua.id WHERE m.active -- Permission Groups -- AND (m.requestor_grp IS NULL OR upgad.id IS NOT NULL) -- Optional Requestor Group? AND (m.usr_grp IS NULL OR upgad.id IS NOT NULL) -- Org Units AND (m.pickup_ou IS NULL OR (puoua.id IS NOT NULL AND (puoua.distance = 0 OR NOT m.strict_ou_match))) AND (m.request_ou IS NULL OR (rqoua.id IS NOT NULL AND (rqoua.distance = 0 OR NOT m.strict_ou_match))) AND (m.item_owning_ou IS NULL OR (cnoua.id IS NOT NULL AND (cnoua.distance = 0 OR NOT m.strict_ou_match))) AND (m.item_circ_ou IS NULL OR (iooua.id IS NOT NULL AND (iooua.distance = 0 OR NOT m.strict_ou_match))) AND (m.user_home_ou IS NULL OR (uhoua.id IS NOT NULL AND (uhoua.distance = 0 OR NOT m.strict_ou_match))) -- Static User Checks AND (m.juvenile_flag IS NULL OR m.juvenile_flag = user_object.juvenile) -- Static Item Checks AND (m.circ_modifier IS NULL OR m.circ_modifier = item_object.circ_modifier) AND (m.marc_type IS NULL OR m.marc_type = COALESCE(item_object.circ_as_type, rec_descriptor.item_type)) AND (m.marc_form IS NULL OR m.marc_form = rec_descriptor.item_form) AND (m.marc_bib_level IS NULL OR m.marc_bib_level = rec_descriptor.bib_level) AND (m.marc_vr_format IS NULL OR m.marc_vr_format = rec_descriptor.vr_format) AND (m.ref_flag IS NULL OR m.ref_flag = item_object.ref) AND (m.item_age IS NULL OR (my_item_age IS NOT NULL AND m.item_age > my_item_age)) ORDER BY -- Permission Groups CASE WHEN rpgad.distance IS NOT NULL THEN 2^(2*weights.requestor_grp - (rpgad.distance/denominator)) ELSE 0.0 END + CASE WHEN upgad.distance IS NOT NULL THEN 2^(2*weights.usr_grp - (upgad.distance/denominator)) ELSE 0.0 END + -- Org Units CASE WHEN puoua.distance IS NOT NULL THEN 2^(2*weights.pickup_ou - (puoua.distance/denominator)) ELSE 0.0 END + CASE WHEN rqoua.distance IS NOT NULL THEN 2^(2*weights.request_ou - (rqoua.distance/denominator)) ELSE 0.0 END + CASE WHEN cnoua.distance IS NOT NULL THEN 2^(2*weights.item_owning_ou - (cnoua.distance/denominator)) ELSE 0.0 END + CASE WHEN iooua.distance IS NOT NULL THEN 2^(2*weights.item_circ_ou - (iooua.distance/denominator)) ELSE 0.0 END + CASE WHEN uhoua.distance IS NOT NULL THEN 2^(2*weights.user_home_ou - (uhoua.distance/denominator)) ELSE 0.0 END + -- Static User Checks -- Note: 4^x is equiv to 2^(2*x) CASE WHEN m.juvenile_flag IS NOT NULL THEN 4^weights.juvenile_flag ELSE 0.0 END + -- Static Item Checks CASE WHEN m.circ_modifier IS NOT NULL THEN 4^weights.circ_modifier ELSE 0.0 END + CASE WHEN m.marc_type IS NOT NULL THEN 4^weights.marc_type ELSE 0.0 END + CASE WHEN m.marc_form IS NOT NULL THEN 4^weights.marc_form ELSE 0.0 END + CASE WHEN m.marc_vr_format IS NOT NULL THEN 4^weights.marc_vr_format ELSE 0.0 END + CASE WHEN m.ref_flag IS NOT NULL THEN 4^weights.ref_flag ELSE 0.0 END + -- Item age has a slight adjustment to weight based on value. -- This should ensure that a shorter age limit comes first when all else is equal. -- NOTE: This assumes that intervals will normally be in days. CASE WHEN m.item_age IS NOT NULL THEN 4^weights.item_age - 86400/EXTRACT(EPOCH FROM m.item_age) ELSE 0.0 END DESC, -- Final sort on id, so that if two rules have the same sorting in the previous sort they have a defined order -- This prevents "we changed the table order by updating a rule, and we started getting different results" m.id; -- Return just the ID for now RETURN matchpoint.id; END;
Function: action.hold_copy_calculated_proximity(copy_context_ou integer, acp_id bigint, ahr_id integer)
Returns: numeric
Language: PLPGSQL
DECLARE ahr action.hold_request%ROWTYPE; acp asset.copy%ROWTYPE; acn asset.call_number%ROWTYPE; acl asset.copy_location%ROWTYPE; prox NUMERIC; BEGIN SELECT * INTO ahr FROM action.hold_request WHERE id = ahr_id; SELECT * INTO acp FROM asset.copy WHERE id = acp_id; SELECT * INTO acn FROM asset.call_number WHERE id = acp.call_number; SELECT * INTO acl FROM asset.copy_location WHERE id = acp.location; IF copy_context_ou IS NULL THEN copy_context_ou := acp.circ_lib; END IF; SELECT action.copy_calculated_proximity( ahr.pickup_lib, ahr.request_lib, copy_context_ou, acp.circ_modifier, acn.owning_lib, acl.owning_lib ) INTO prox; RETURN prox; END;
Function: action.hold_copy_calculated_proximity_update()
Returns: trigger
Language: PLPGSQL
BEGIN NEW.proximity := action.hold_copy_calculated_proximity(NEW.hold,NEW.target_copy); RETURN NEW; END;
Function: action.hold_request_clear_map()
Returns: trigger
Language: PLPGSQL
BEGIN DELETE FROM action.hold_copy_map WHERE hold = NEW.id; RETURN NEW; END;
Function: action.hold_request_permit_test(match_requestor integer, match_user integer, match_item bigint, request_ou integer, pickup_ou integer)
Returns: SET OF matrix_test_result
Language: SQL
SELECT * FROM action.hold_request_permit_test( $1, $2, $3, $4, $5, FALSE );
Function: action.hold_request_permit_test(retargetting integer, match_requestor integer, match_user bigint, match_item integer, request_ou integer, pickup_ou boolean)
Returns: SET OF matrix_test_result
Language: PLPGSQL
DECLARE matchpoint_id INT; user_object actor.usr%ROWTYPE; age_protect_object config.rule_age_hold_protect%ROWTYPE; standing_penalty config.standing_penalty%ROWTYPE; transit_range_ou_type actor.org_unit_type%ROWTYPE; transit_source actor.org_unit%ROWTYPE; item_object asset.copy%ROWTYPE; item_cn_object asset.call_number%ROWTYPE; item_status_object config.copy_status%ROWTYPE; item_location_object asset.copy_location%ROWTYPE; ou_skip actor.org_unit_setting%ROWTYPE; calc_age_prox actor.org_unit_setting%ROWTYPE; result action.matrix_test_result; hold_test config.hold_matrix_matchpoint%ROWTYPE; use_active_date TEXT; prox_ou INT; age_protect_date TIMESTAMP WITH TIME ZONE; hold_count INT; hold_transit_prox NUMERIC; frozen_hold_count INT; context_org_list INT[]; done BOOL := FALSE; hold_penalty TEXT; v_pickup_ou ALIAS FOR pickup_ou; v_request_ou ALIAS FOR request_ou; item_prox INT; pickup_prox INT; BEGIN SELECT INTO user_object * FROM actor.usr WHERE id = match_user; SELECT INTO context_org_list ARRAY_AGG(id) FROM actor.org_unit_full_path( v_pickup_ou ); result.success := TRUE; -- The HOLD penalty block only applies to new holds. -- The CAPTURE penalty block applies to existing holds. hold_penalty := 'HOLD'; IF retargetting THEN hold_penalty := 'CAPTURE'; END IF; -- Fail if we couldn't find a user IF user_object.id IS NULL THEN result.fail_part := 'no_user'; result.success := FALSE; done := TRUE; RETURN NEXT result; RETURN; END IF; SELECT INTO item_object * FROM asset.copy WHERE id = match_item; -- Fail if we couldn't find a copy IF item_object.id IS NULL THEN result.fail_part := 'no_item'; result.success := FALSE; done := TRUE; RETURN NEXT result; RETURN; END IF; SELECT INTO matchpoint_id action.find_hold_matrix_matchpoint(v_pickup_ou, v_request_ou, match_item, match_user, match_requestor); result.matchpoint := matchpoint_id; SELECT INTO ou_skip * FROM actor.org_unit_setting WHERE name = 'circ.holds.target_skip_me' AND org_unit = item_object.circ_lib; -- Fail if the circ_lib for the item has circ.holds.target_skip_me set to true IF ou_skip.id IS NOT NULL AND ou_skip.value = 'true' THEN result.fail_part := 'circ.holds.target_skip_me'; result.success := FALSE; done := TRUE; RETURN NEXT result; RETURN; END IF; -- Fail if user is barred IF user_object.barred IS TRUE THEN result.fail_part := 'actor.usr.barred'; result.success := FALSE; done := TRUE; RETURN NEXT result; RETURN; END IF; SELECT INTO item_cn_object * FROM asset.call_number WHERE id = item_object.call_number; SELECT INTO item_status_object * FROM config.copy_status WHERE id = item_object.status; SELECT INTO item_location_object * FROM asset.copy_location WHERE id = item_object.location; -- Fail if we couldn't find any matchpoint (requires a default) IF matchpoint_id IS NULL THEN result.fail_part := 'no_matchpoint'; result.success := FALSE; done := TRUE; RETURN NEXT result; RETURN; END IF; SELECT INTO hold_test * FROM config.hold_matrix_matchpoint WHERE id = matchpoint_id; IF hold_test.holdable IS FALSE THEN result.fail_part := 'config.hold_matrix_test.holdable'; result.success := FALSE; done := TRUE; RETURN NEXT result; END IF; IF item_object.holdable IS FALSE THEN result.fail_part := 'item.holdable'; result.success := FALSE; done := TRUE; RETURN NEXT result; END IF; IF item_status_object.holdable IS FALSE THEN result.fail_part := 'status.holdable'; result.success := FALSE; done := TRUE; RETURN NEXT result; END IF; IF item_location_object.holdable IS FALSE THEN result.fail_part := 'location.holdable'; result.success := FALSE; done := TRUE; RETURN NEXT result; END IF; IF hold_test.transit_range IS NOT NULL THEN SELECT INTO transit_range_ou_type * FROM actor.org_unit_type WHERE id = hold_test.transit_range; IF hold_test.distance_is_from_owner THEN SELECT INTO transit_source ou.* FROM actor.org_unit ou JOIN asset.call_number cn ON (cn.owning_lib = ou.id) WHERE cn.id = item_object.call_number; ELSE SELECT INTO transit_source * FROM actor.org_unit WHERE id = item_object.circ_lib; END IF; PERFORM * FROM actor.org_unit_descendants( transit_source.id, transit_range_ou_type.depth ) WHERE id = v_pickup_ou; IF NOT FOUND THEN result.fail_part := 'transit_range'; result.success := FALSE; done := TRUE; RETURN NEXT result; END IF; END IF; -- Proximity of user's home_ou to the pickup_lib to see if penalty should be ignored. SELECT INTO pickup_prox prox FROM actor.org_unit_proximity WHERE from_org = user_object.home_ou AND to_org = v_pickup_ou; -- Proximity of user's home_ou to the items' lib to see if penalty should be ignored. IF hold_test.distance_is_from_owner THEN SELECT INTO item_prox prox FROM actor.org_unit_proximity WHERE from_org = user_object.home_ou AND to_org = item_cn_object.owning_lib; ELSE SELECT INTO item_prox prox FROM actor.org_unit_proximity WHERE from_org = user_object.home_ou AND to_org = item_object.circ_lib; END IF; FOR standing_penalty IN SELECT DISTINCT csp.* FROM actor.usr_standing_penalty usp JOIN config.standing_penalty csp ON (csp.id = usp.standing_penalty) WHERE usr = match_user AND usp.org_unit IN ( SELECT * FROM unnest(context_org_list) ) AND (usp.stop_date IS NULL or usp.stop_date > NOW()) AND (csp.ignore_proximity IS NULL OR csp.ignore_proximity < item_prox OR csp.ignore_proximity < pickup_prox) AND csp.block_list LIKE '%' || hold_penalty || '%' LOOP result.fail_part := standing_penalty.name; result.success := FALSE; done := TRUE; RETURN NEXT result; END LOOP; IF hold_test.stop_blocked_user IS TRUE THEN FOR standing_penalty IN SELECT DISTINCT csp.* FROM actor.usr_standing_penalty usp JOIN config.standing_penalty csp ON (csp.id = usp.standing_penalty) WHERE usr = match_user AND usp.org_unit IN ( SELECT * FROM unnest(context_org_list) ) AND (usp.stop_date IS NULL or usp.stop_date > NOW()) AND csp.block_list LIKE '%CIRC%' LOOP result.fail_part := standing_penalty.name; result.success := FALSE; done := TRUE; RETURN NEXT result; END LOOP; END IF; IF hold_test.max_holds IS NOT NULL AND NOT retargetting THEN SELECT INTO hold_count COUNT(*) FROM action.hold_request WHERE usr = match_user AND fulfillment_time IS NULL AND cancel_time IS NULL AND CASE WHEN hold_test.include_frozen_holds THEN TRUE ELSE frozen IS FALSE END; IF hold_count >= hold_test.max_holds THEN result.fail_part := 'config.hold_matrix_test.max_holds'; result.success := FALSE; done := TRUE; RETURN NEXT result; END IF; END IF; IF item_object.age_protect IS NOT NULL THEN SELECT INTO age_protect_object * FROM config.rule_age_hold_protect WHERE id = item_object.age_protect; IF hold_test.distance_is_from_owner THEN SELECT INTO use_active_date value FROM actor.org_unit_ancestor_setting('circ.holds.age_protect.active_date', item_cn_object.owning_lib); ELSE SELECT INTO use_active_date value FROM actor.org_unit_ancestor_setting('circ.holds.age_protect.active_date', item_object.circ_lib); END IF; IF use_active_date = 'true' THEN age_protect_date := COALESCE(item_object.active_date, NOW()); ELSE age_protect_date := item_object.create_date; END IF; IF age_protect_date + age_protect_object.age > NOW() THEN SELECT INTO calc_age_prox * FROM actor.org_unit_setting WHERE name = 'circ.holds.calculated_age_proximity' AND org_unit = item_object.circ_lib; IF hold_test.distance_is_from_owner THEN prox_ou := item_cn_object.owning_lib; ELSE prox_ou := item_object.circ_lib; END IF; IF calc_age_prox.id IS NOT NULL AND calc_age_prox.value = 'true' THEN SELECT INTO hold_transit_prox action.copy_calculated_proximity( v_pickup_ou, v_request_ou, prox_ou, item_object.circ_modifier, item_cn_object.owning_lib, item_location_object.owning_lib ); ELSE SELECT INTO hold_transit_prox prox::NUMERIC FROM actor.org_unit_proximity WHERE from_org = prox_ou AND to_org = v_pickup_ou; END IF; IF hold_transit_prox > age_protect_object.prox::NUMERIC THEN result.fail_part := 'config.rule_age_hold_protect.prox'; result.success := FALSE; done := TRUE; RETURN NEXT result; END IF; END IF; END IF; IF NOT done THEN RETURN NEXT result; END IF; RETURN; END;
Function: action.hold_request_regen_copy_maps(copy_ids integer, hold_id integer[])
Returns: void
Language: SQL
DELETE FROM action.hold_copy_map WHERE hold = $1; INSERT INTO action.hold_copy_map (hold, target_copy) SELECT DISTINCT $1, UNNEST($2);
Function: action.hold_retarget_permit_test(match_requestor integer, match_user integer, match_item bigint, request_ou integer, pickup_ou integer)
Returns: SET OF matrix_test_result
Language: SQL
SELECT * FROM action.hold_request_permit_test( $1, $2, $3, $4, $5, TRUE );
Function: action.item_user_circ_test(integer, bigint, integer)
Returns: SET OF circ_matrix_test_result
Language: SQL
SELECT * FROM action.item_user_circ_test( $1, $2, $3, FALSE );
Function: action.item_user_circ_test(renewal integer, match_user bigint, match_item integer, circ_ou boolean)
Returns: SET OF circ_matrix_test_result
Language: PLPGSQL
DECLARE user_object actor.usr%ROWTYPE; standing_penalty config.standing_penalty%ROWTYPE; item_object asset.copy%ROWTYPE; item_status_object config.copy_status%ROWTYPE; item_location_object asset.copy_location%ROWTYPE; result action.circ_matrix_test_result; circ_test action.found_circ_matrix_matchpoint; circ_matchpoint config.circ_matrix_matchpoint%ROWTYPE; circ_limit_set config.circ_limit_set%ROWTYPE; hold_ratio action.hold_stats%ROWTYPE; penalty_type TEXT; items_out INT; context_org_list INT[]; permit_renew TEXT; done BOOL := FALSE; item_prox INT; home_prox INT; BEGIN -- Assume success unless we hit a failure condition result.success := TRUE; -- Need user info to look up matchpoints SELECT INTO user_object * FROM actor.usr WHERE id = match_user AND NOT deleted; -- (Insta)Fail if we couldn't find the user IF user_object.id IS NULL THEN result.fail_part := 'no_user'; result.success := FALSE; done := TRUE; RETURN NEXT result; RETURN; END IF; -- Need item info to look up matchpoints SELECT INTO item_object * FROM asset.copy WHERE id = match_item AND NOT deleted; -- (Insta)Fail if we couldn't find the item IF item_object.id IS NULL THEN result.fail_part := 'no_item'; result.success := FALSE; done := TRUE; RETURN NEXT result; RETURN; END IF; SELECT INTO circ_test * FROM action.find_circ_matrix_matchpoint(circ_ou, item_object, user_object, renewal); circ_matchpoint := circ_test.matchpoint; result.matchpoint := circ_matchpoint.id; result.circulate := circ_matchpoint.circulate; result.duration_rule := circ_matchpoint.duration_rule; result.recurring_fine_rule := circ_matchpoint.recurring_fine_rule; result.max_fine_rule := circ_matchpoint.max_fine_rule; result.hard_due_date := circ_matchpoint.hard_due_date; result.renewals := circ_matchpoint.renewals; result.grace_period := circ_matchpoint.grace_period; result.buildrows := circ_test.buildrows; -- (Insta)Fail if we couldn't find a matchpoint IF circ_test.success = false THEN result.fail_part := 'no_matchpoint'; result.success := FALSE; done := TRUE; RETURN NEXT result; RETURN; END IF; -- All failures before this point are non-recoverable -- Below this point are possibly overridable failures -- Fail if the user is barred IF user_object.barred IS TRUE THEN result.fail_part := 'actor.usr.barred'; result.success := FALSE; done := TRUE; RETURN NEXT result; END IF; -- Fail if the item can't circulate IF item_object.circulate IS FALSE THEN result.fail_part := 'asset.copy.circulate'; result.success := FALSE; done := TRUE; RETURN NEXT result; END IF; -- Fail if the item isn't in a circulateable status on a non-renewal IF NOT renewal AND item_object.status <> 8 AND item_object.status NOT IN ( (SELECT id FROM config.copy_status WHERE is_available) ) THEN result.fail_part := 'asset.copy.status'; result.success := FALSE; done := TRUE; RETURN NEXT result; -- Alternately, fail if the item isn't checked out on a renewal ELSIF renewal AND item_object.status <> 1 THEN result.fail_part := 'asset.copy.status'; result.success := FALSE; done := TRUE; RETURN NEXT result; END IF; -- Fail if the item can't circulate because of the shelving location SELECT INTO item_location_object * FROM asset.copy_location WHERE id = item_object.location; IF item_location_object.circulate IS FALSE THEN result.fail_part := 'asset.copy_location.circulate'; result.success := FALSE; done := TRUE; RETURN NEXT result; END IF; -- Use Circ OU for penalties and such SELECT INTO context_org_list ARRAY_AGG(id) FROM actor.org_unit_full_path( circ_ou ); -- Proximity of user's home_ou to circ_ou to see if penalties should be ignored. SELECT INTO home_prox prox FROM actor.org_unit_proximity WHERE from_org = user_object.home_ou AND to_org = circ_ou; -- Proximity of user's home_ou to item circ_lib to see if penalties should be ignored. SELECT INTO item_prox prox FROM actor.org_unit_proximity WHERE from_org = user_object.home_ou AND to_org = item_object.circ_lib; IF renewal THEN penalty_type = '%RENEW%'; ELSE penalty_type = '%CIRC%'; END IF; FOR standing_penalty IN SELECT DISTINCT csp.* FROM actor.usr_standing_penalty usp JOIN config.standing_penalty csp ON (csp.id = usp.standing_penalty) WHERE usr = match_user AND usp.org_unit IN ( SELECT * FROM unnest(context_org_list) ) AND (usp.stop_date IS NULL or usp.stop_date > NOW()) AND (csp.ignore_proximity IS NULL OR csp.ignore_proximity < home_prox OR csp.ignore_proximity < item_prox) AND csp.block_list LIKE penalty_type LOOP -- override PATRON_EXCEEDS_FINES penalty for renewals based on org setting IF renewal AND standing_penalty.name = 'PATRON_EXCEEDS_FINES' THEN SELECT INTO permit_renew value FROM actor.org_unit_ancestor_setting('circ.permit_renew_when_exceeds_fines', circ_ou); IF permit_renew IS NOT NULL AND permit_renew ILIKE 'true' THEN CONTINUE; END IF; END IF; result.fail_part := standing_penalty.name; result.success := FALSE; done := TRUE; RETURN NEXT result; END LOOP; -- Fail if the test is set to hard non-circulating IF circ_matchpoint.circulate IS FALSE THEN result.fail_part := 'config.circ_matrix_test.circulate'; result.success := FALSE; done := TRUE; RETURN NEXT result; END IF; -- Fail if the total copy-hold ratio is too low IF circ_matchpoint.total_copy_hold_ratio IS NOT NULL THEN SELECT INTO hold_ratio * FROM action.copy_related_hold_stats(match_item); IF hold_ratio.total_copy_ratio IS NOT NULL AND hold_ratio.total_copy_ratio < circ_matchpoint.total_copy_hold_ratio THEN result.fail_part := 'config.circ_matrix_test.total_copy_hold_ratio'; result.success := FALSE; done := TRUE; RETURN NEXT result; END IF; END IF; -- Fail if the available copy-hold ratio is too low IF circ_matchpoint.available_copy_hold_ratio IS NOT NULL THEN IF hold_ratio.hold_count IS NULL THEN SELECT INTO hold_ratio * FROM action.copy_related_hold_stats(match_item); END IF; IF hold_ratio.available_copy_ratio IS NOT NULL AND hold_ratio.available_copy_ratio < circ_matchpoint.available_copy_hold_ratio THEN result.fail_part := 'config.circ_matrix_test.available_copy_hold_ratio'; result.success := FALSE; done := TRUE; RETURN NEXT result; END IF; END IF; -- Fail if the user has too many items out by defined limit sets FOR circ_limit_set IN SELECT ccls.* FROM config.circ_limit_set ccls JOIN config.circ_matrix_limit_set_map ccmlsm ON ccmlsm.limit_set = ccls.id WHERE ccmlsm.active AND ( ccmlsm.matchpoint = circ_matchpoint.id OR ( ccmlsm.matchpoint IN (SELECT * FROM unnest(result.buildrows)) AND ccmlsm.fallthrough ) ) LOOP IF circ_limit_set.items_out > 0 AND NOT renewal THEN SELECT INTO context_org_list ARRAY_AGG(aou.id) FROM actor.org_unit_full_path( circ_ou ) aou JOIN actor.org_unit_type aout ON aou.ou_type = aout.id WHERE aout.depth >= circ_limit_set.depth; IF circ_limit_set.global THEN WITH RECURSIVE descendant_depth AS ( SELECT ou.id, ou.parent_ou FROM actor.org_unit ou WHERE ou.id IN (SELECT * FROM unnest(context_org_list)) UNION SELECT ou.id, ou.parent_ou FROM actor.org_unit ou JOIN descendant_depth ot ON (ot.id = ou.parent_ou) ) SELECT INTO context_org_list ARRAY_AGG(ou.id) FROM actor.org_unit ou JOIN descendant_depth USING (id); END IF; SELECT INTO items_out COUNT(DISTINCT circ.id) FROM action.circulation circ JOIN asset.copy copy ON (copy.id = circ.target_copy) LEFT JOIN action.circulation_limit_group_map aclgm ON (circ.id = aclgm.circ) WHERE circ.usr = match_user AND circ.circ_lib IN (SELECT * FROM unnest(context_org_list)) AND circ.checkin_time IS NULL AND circ.xact_finish IS NULL AND (circ.stop_fines IN ('MAXFINES','LONGOVERDUE') OR circ.stop_fines IS NULL) AND (copy.circ_modifier IN (SELECT circ_mod FROM config.circ_limit_set_circ_mod_map WHERE limit_set = circ_limit_set.id) OR copy.location IN (SELECT copy_loc FROM config.circ_limit_set_copy_loc_map WHERE limit_set = circ_limit_set.id) OR aclgm.limit_group IN (SELECT limit_group FROM config.circ_limit_set_group_map WHERE limit_set = circ_limit_set.id) ); IF items_out >= circ_limit_set.items_out THEN result.fail_part := 'config.circ_matrix_circ_mod_test'; result.success := FALSE; done := TRUE; RETURN NEXT result; END IF; END IF; SELECT INTO result.limit_groups result.limit_groups || ARRAY_AGG(limit_group) FROM config.circ_limit_set_group_map WHERE limit_set = circ_limit_set.id AND NOT check_only; END LOOP; -- If we passed everything, return the successful matchpoint IF NOT done THEN RETURN NEXT result; END IF; RETURN; END;
Function: action.item_user_renew_test(integer, bigint, integer)
Returns: SET OF circ_matrix_test_result
Language: SQL
SELECT * FROM action.item_user_circ_test( $1, $2, $3, TRUE );
Function: action.link_circ_limit_groups(bigint, integer[])
Returns: void
Language: SQL
INSERT INTO action.circulation_limit_group_map(circ, limit_group) SELECT $1, id FROM config.circ_limit_group WHERE id IN (SELECT * FROM UNNEST($2));
Function: action.maintain_usr_circ_history()
Returns: trigger
Language: PLPGSQL
DECLARE cur_circ BIGINT; first_circ BIGINT; BEGIN -- Any retention value signifies history is enabled. -- This assumes that clearing these values via external -- process deletes the action.usr_circ_history rows. -- TODO: replace these settings w/ a single bool setting? PERFORM 1 FROM actor.usr_setting WHERE usr = NEW.usr AND value IS NOT NULL AND name IN ( 'history.circ.retention_age', 'history.circ.retention_start' ); IF NOT FOUND THEN RETURN NEW; END IF; IF TG_OP = 'INSERT' AND NEW.parent_circ IS NULL THEN -- Starting a new circulation. Insert the history row. INSERT INTO action.usr_circ_history (usr, xact_start, target_copy, due_date, source_circ) VALUES ( NEW.usr, NEW.xact_start, NEW.target_copy, NEW.due_date, NEW.id ); RETURN NEW; END IF; -- find the first and last circs in the circ chain -- for the currently modified circ. FOR cur_circ IN SELECT id FROM action.circ_chain(NEW.id) LOOP IF first_circ IS NULL THEN first_circ := cur_circ; CONTINUE; END IF; -- Allow the loop to continue so that at as the loop -- completes cur_circ points to the final circulation. END LOOP; IF NEW.id <> cur_circ THEN -- Modifying an intermediate circ. Ignore it. RETURN NEW; END IF; -- Update the due_date/checkin_time on the history row if the current -- circ is the last circ in the chain and an update is warranted. UPDATE action.usr_circ_history SET due_date = NEW.due_date, checkin_time = NEW.checkin_time WHERE source_circ = first_circ AND ( due_date <> NEW.due_date OR ( (checkin_time IS NULL AND NEW.checkin_time IS NOT NULL) OR (checkin_time IS NOT NULL AND NEW.checkin_time IS NULL) OR (checkin_time <> NEW.checkin_time) ) ); RETURN NEW; END;
Function: action.purge_circulations()
Returns: integer
Language: PLPGSQL
DECLARE org_keep_age INTERVAL; org_use_last BOOL = false; org_age_is_min BOOL = false; org_keep_count INT; keep_age INTERVAL; target_acp RECORD; circ_chain_head action.circulation%ROWTYPE; circ_chain_tail action.circulation%ROWTYPE; count_purged INT; num_incomplete INT; last_finished TIMESTAMP WITH TIME ZONE; BEGIN count_purged := 0; SELECT value::INTERVAL INTO org_keep_age FROM config.global_flag WHERE name = 'history.circ.retention_age' AND enabled; SELECT value::INT INTO org_keep_count FROM config.global_flag WHERE name = 'history.circ.retention_count' AND enabled; IF org_keep_count IS NULL THEN RETURN count_purged; -- Gimme a count to keep, or I keep them all, forever END IF; SELECT enabled INTO org_use_last FROM config.global_flag WHERE name = 'history.circ.retention_uses_last_finished'; SELECT enabled INTO org_age_is_min FROM config.global_flag WHERE name = 'history.circ.retention_age_is_min'; -- First, find copies with more than keep_count non-renewal circs FOR target_acp IN SELECT target_copy, COUNT(*) AS total_real_circs FROM action.circulation WHERE parent_circ IS NULL AND xact_finish IS NOT NULL GROUP BY target_copy HAVING COUNT(*) > org_keep_count LOOP -- And, for those, select circs that are finished and older than keep_age FOR circ_chain_head IN -- For reference, the subquery uses a window function to order the circs newest to oldest and number them -- The outer query then uses that information to skip the most recent set the library wants to keep -- End result is we don't care what order they come out in, as they are all potentials for deletion. SELECT ac.* FROM action.circulation ac JOIN ( SELECT rank() OVER (ORDER BY xact_start DESC), ac.id FROM action.circulation ac WHERE ac.target_copy = target_acp.target_copy AND ac.parent_circ IS NULL ORDER BY ac.xact_start ) ranked USING (id) WHERE ranked.rank > org_keep_count LOOP SELECT * INTO circ_chain_tail FROM action.circ_chain(circ_chain_head.id) ORDER BY xact_start DESC LIMIT 1; SELECT COUNT(CASE WHEN xact_finish IS NULL THEN 1 ELSE NULL END), MAX(xact_finish) INTO num_incomplete, last_finished FROM action.circ_chain(circ_chain_head.id); CONTINUE WHEN circ_chain_tail.xact_finish IS NULL OR num_incomplete > 0; IF NOT org_use_last THEN last_finished := circ_chain_tail.xact_finish; END IF; keep_age := COALESCE( org_keep_age, '2000 years'::INTERVAL ); IF org_age_is_min THEN keep_age := GREATEST( keep_age, org_keep_age ); END IF; CONTINUE WHEN AGE(NOW(), last_finished) < keep_age; -- We've passed the purging tests, purge the circ chain starting at the end -- A trigger should auto-purge the rest of the chain. DELETE FROM action.circulation WHERE id = circ_chain_tail.id; count_purged := count_purged + 1; END LOOP; END LOOP; return count_purged; END;
Function: action.purge_holds()
Returns: integer
Language: PLPGSQL
DECLARE current_hold RECORD; purged_holds INT; cgf_d INTERVAL; cgf_f INTERVAL; cgf_c INTERVAL; prev_usr INT; user_start TIMESTAMPTZ; user_age INTERVAL; user_count INT; BEGIN purged_holds := 0; SELECT INTO cgf_d value::INTERVAL FROM config.global_flag WHERE name = 'history.hold.retention_age' AND enabled; SELECT INTO cgf_f value::INTERVAL FROM config.global_flag WHERE name = 'history.hold.retention_age_fulfilled' AND enabled; SELECT INTO cgf_c value::INTERVAL FROM config.global_flag WHERE name = 'history.hold.retention_age_canceled' AND enabled; FOR current_hold IN SELECT rank() OVER (PARTITION BY usr ORDER BY COALESCE(fulfillment_time, cancel_time) DESC), cgf_cs.value::INTERVAL as cgf_cs, ahr.* FROM action.hold_request ahr LEFT JOIN config.global_flag cgf_cs ON (ahr.cancel_cause IS NOT NULL AND cgf_cs.name = 'history.hold.retention_age_canceled_' || ahr.cancel_cause AND cgf_cs.enabled) WHERE (fulfillment_time IS NOT NULL OR cancel_time IS NOT NULL) LOOP IF prev_usr IS NULL OR prev_usr != current_hold.usr THEN prev_usr := current_hold.usr; SELECT INTO user_start oils_json_to_text(value)::TIMESTAMPTZ FROM actor.usr_setting WHERE usr = prev_usr AND name = 'history.hold.retention_start'; SELECT INTO user_age oils_json_to_text(value)::INTERVAL FROM actor.usr_setting WHERE usr = prev_usr AND name = 'history.hold.retention_age'; SELECT INTO user_count oils_json_to_text(value)::INT FROM actor.usr_setting WHERE usr = prev_usr AND name = 'history.hold.retention_count'; IF user_start IS NOT NULL THEN user_age := LEAST(user_age, AGE(NOW(), user_start)); END IF; IF user_count IS NULL THEN user_count := 1000; -- Assumption based on the user visible holds routine END IF; END IF; -- Library keep age trumps user keep anything, for purposes of being able to hold on to things when staff canceled and such. IF current_hold.fulfillment_time IS NOT NULL AND current_hold.fulfillment_time > NOW() - COALESCE(cgf_f, cgf_d) THEN CONTINUE; END IF; IF current_hold.cancel_time IS NOT NULL AND current_hold.cancel_time > NOW() - COALESCE(current_hold.cgf_cs, cgf_c, cgf_d) THEN CONTINUE; END IF; -- User keep age needs combining with count. If too old AND within the count, keep! IF user_start IS NOT NULL AND COALESCE(current_hold.fulfillment_time, current_hold.cancel_time) > NOW() - user_age AND current_hold.rank <= user_count THEN CONTINUE; END IF; -- All checks should have passed, delete! DELETE FROM action.hold_request WHERE id = current_hold.id; purged_holds := purged_holds + 1; END LOOP; RETURN purged_holds; END;
Function: action.push_circ_due_time()
Returns: trigger
Language: PLPGSQL
DECLARE proper_tz TEXT := COALESCE( oils_json_to_text(( SELECT value FROM actor.org_unit_ancestor_setting('lib.timezone',NEW.circ_lib) LIMIT 1 )), CURRENT_SETTING('timezone') ); BEGIN IF (EXTRACT(EPOCH FROM NEW.duration)::INT % EXTRACT(EPOCH FROM '1 day'::INTERVAL)::INT) = 0 -- day-granular duration AND SUBSTRING((NEW.due_date AT TIME ZONE proper_tz)::TIME::TEXT FROM 1 FOR 8) <> '23:59:59' THEN -- has not yet been pushed NEW.due_date = ((NEW.due_date AT TIME ZONE proper_tz)::DATE + '1 day'::INTERVAL - '1 second'::INTERVAL) || ' ' || proper_tz; END IF; RETURN NEW; END;
Function: action.summarize_all_circ_chain(ctx_circ_id integer)
Returns: circ_chain_summary
Language: PLPGSQL
DECLARE -- first circ in the chain circ_0 action.all_circulation_slim%ROWTYPE; -- last circ in the chain circ_n action.all_circulation_slim%ROWTYPE; -- circ chain under construction chain action.circ_chain_summary; tmp_circ action.all_circulation_slim%ROWTYPE; BEGIN chain.num_circs := 0; FOR tmp_circ IN SELECT * FROM action.all_circ_chain(ctx_circ_id) LOOP IF chain.num_circs = 0 THEN circ_0 := tmp_circ; END IF; chain.num_circs := chain.num_circs + 1; circ_n := tmp_circ; END LOOP; chain.start_time := circ_0.xact_start; chain.last_stop_fines := circ_n.stop_fines; chain.last_stop_fines_time := circ_n.stop_fines_time; chain.last_checkin_time := circ_n.checkin_time; chain.last_checkin_scan_time := circ_n.checkin_scan_time; SELECT INTO chain.checkout_workstation name FROM actor.workstation WHERE id = circ_0.workstation; SELECT INTO chain.last_checkin_workstation name FROM actor.workstation WHERE id = circ_n.checkin_workstation; IF chain.num_circs > 1 THEN chain.last_renewal_time := circ_n.xact_start; SELECT INTO chain.last_renewal_workstation name FROM actor.workstation WHERE id = circ_n.workstation; END IF; RETURN chain; END;
Function: action.summarize_circ_chain(ctx_circ_id bigint)
Returns: circ_chain_summary
Language: PLPGSQL
DECLARE -- first circ in the chain circ_0 action.circulation%ROWTYPE; -- last circ in the chain circ_n action.circulation%ROWTYPE; -- circ chain under construction chain action.circ_chain_summary; tmp_circ action.circulation%ROWTYPE; BEGIN chain.num_circs := 0; FOR tmp_circ IN SELECT * FROM action.circ_chain(ctx_circ_id) LOOP IF chain.num_circs = 0 THEN circ_0 := tmp_circ; END IF; chain.num_circs := chain.num_circs + 1; circ_n := tmp_circ; END LOOP; chain.start_time := circ_0.xact_start; chain.last_stop_fines := circ_n.stop_fines; chain.last_stop_fines_time := circ_n.stop_fines_time; chain.last_checkin_time := circ_n.checkin_time; chain.last_checkin_scan_time := circ_n.checkin_scan_time; SELECT INTO chain.checkout_workstation name FROM actor.workstation WHERE id = circ_0.workstation; SELECT INTO chain.last_checkin_workstation name FROM actor.workstation WHERE id = circ_n.checkin_workstation; IF chain.num_circs > 1 THEN chain.last_renewal_time := circ_n.xact_start; SELECT INTO chain.last_renewal_workstation name FROM actor.workstation WHERE id = circ_n.workstation; END IF; RETURN chain; END;
Function: action.survey_response_answer_date_fixup()
Returns: trigger
Language: PLPGSQL
BEGIN NEW.answer_date := NOW(); RETURN NEW; END;
Function: action.usr_visible_holds(usr_id integer)
Returns: SET OF hold_request
Language: PLPGSQL
DECLARE h action.hold_request%ROWTYPE; view_age INTERVAL; view_count INT; usr_view_count actor.usr_setting%ROWTYPE; usr_view_age actor.usr_setting%ROWTYPE; usr_view_start actor.usr_setting%ROWTYPE; BEGIN SELECT * INTO usr_view_count FROM actor.usr_setting WHERE usr = usr_id AND name = 'history.hold.retention_count'; SELECT * INTO usr_view_age FROM actor.usr_setting WHERE usr = usr_id AND name = 'history.hold.retention_age'; SELECT * INTO usr_view_start FROM actor.usr_setting WHERE usr = usr_id AND name = 'history.hold.retention_start'; FOR h IN SELECT * FROM action.hold_request WHERE usr = usr_id AND fulfillment_time IS NULL AND cancel_time IS NULL ORDER BY request_time DESC LOOP RETURN NEXT h; END LOOP; IF usr_view_start.value IS NULL THEN RETURN; END IF; IF usr_view_age.value IS NOT NULL THEN -- User opted in and supplied a retention age IF oils_json_to_text(usr_view_age.value)::INTERVAL > AGE(NOW(), oils_json_to_text(usr_view_start.value)::TIMESTAMPTZ) THEN view_age := AGE(NOW(), oils_json_to_text(usr_view_start.value)::TIMESTAMPTZ); ELSE view_age := oils_json_to_text(usr_view_age.value)::INTERVAL; END IF; ELSE -- User opted in view_age := AGE(NOW(), oils_json_to_text(usr_view_start.value)::TIMESTAMPTZ); END IF; IF usr_view_count.value IS NOT NULL THEN view_count := oils_json_to_text(usr_view_count.value)::INT; ELSE view_count := 1000; END IF; -- show some fulfilled/canceled holds FOR h IN SELECT * FROM action.hold_request WHERE usr = usr_id AND ( fulfillment_time IS NOT NULL OR cancel_time IS NOT NULL ) AND COALESCE(fulfillment_time, cancel_time) > NOW() - view_age ORDER BY COALESCE(fulfillment_time, cancel_time) DESC LIMIT view_count LOOP RETURN NEXT h; END LOOP; RETURN; END;
Schema action_trigger
Table: action_trigger.alternate_template
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | NOT NULL | |
action_trigger.event_definition.id | event_def | integer | UNIQUE#1 |
template | text | ||
active | boolean | DEFAULT true | |
config.i18n_locale.code | locale | text | UNIQUE#1 |
message_title | text | ||
message_template | text |
Table: action_trigger.cleanup
F-Key | Name | Type | Description |
---|---|---|---|
module | text | PRIMARY KEY | |
description | text |
Tables referencing this one via Foreign Key Constraints:
Table: action_trigger.collector
F-Key | Name | Type | Description |
---|---|---|---|
module | text | PRIMARY KEY | |
description | text |
Tables referencing this one via Foreign Key Constraints:
Table: action_trigger.environment
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
action_trigger.event_definition.id | event_def | integer | UNIQUE#1 NOT NULL |
path | text | ||
action_trigger.collector.module | collector | text | |
label | text | UNIQUE#1 |
Name | Constraint |
---|---|
environment_label_check | CHECK ((label <> ALL (ARRAY['result'::text, 'target'::text, 'event'::text]))) |
Table: action_trigger.event
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
target | bigint | NOT NULL | |
action_trigger.event_definition.id | event_def | integer | |
add_time | timestamp with time zone | NOT NULL DEFAULT now() | |
run_time | timestamp with time zone | NOT NULL | |
start_time | timestamp with time zone | ||
update_time | timestamp with time zone | ||
complete_time | timestamp with time zone | ||
update_process | integer | ||
state | text | NOT NULL DEFAULT 'pending'::text | |
user_data | text | ||
action_trigger.event_output.id | template_output | bigint | |
action_trigger.event_output.id | error_output | bigint | |
action_trigger.event_output.id | async_output | bigint | |
actor.usr.id | context_user | integer | |
actor.org_unit.id | context_library | integer | |
biblio.record_entry.id | context_bib | bigint | |
context_item | bigint |
Name | Constraint |
---|---|
event_state_check | CHECK ((state = ANY (ARRAY['pending'::text, 'invalid'::text, 'found'::text, 'collecting'::text, 'collected'::text, 'validating'::text, 'valid'::text, 'reacting'::text, 'reacted'::text, 'cleaning'::text, 'complete'::text, 'error'::text]))) |
event_user_data_check | CHECK (((user_data IS NULL) OR is_json(user_data))) |
Table: action_trigger.event_def_group
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | owner | integer | NOT NULL |
action_trigger.hook.key | hook | text | NOT NULL |
active | boolean | NOT NULL DEFAULT true | |
name | text | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: action_trigger.event_def_group_member
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
action_trigger.event_def_group.id | grp | integer | NOT NULL |
action_trigger.event_definition.id | event_def | integer | NOT NULL |
sortable | boolean | NOT NULL DEFAULT true | |
holdings | boolean | NOT NULL DEFAULT false | |
external | boolean | NOT NULL DEFAULT false | |
name | text | NOT NULL |
Table: action_trigger.event_definition
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
active | boolean | NOT NULL DEFAULT true | |
actor.org_unit.id | owner | integer | UNIQUE#2 UNIQUE#1 NOT NULL |
name | text | UNIQUE#2 NOT NULL | |
action_trigger.hook.key | hook | text | UNIQUE#1 NOT NULL |
action_trigger.validator.module | validator | text | UNIQUE#1 NOT NULL |
action_trigger.reactor.module | reactor | text | UNIQUE#1 NOT NULL |
action_trigger.cleanup.module | cleanup_success | text | |
action_trigger.cleanup.module | cleanup_failure | text | |
delay | interval | UNIQUE#1 NOT NULL DEFAULT '00:05:00'::interval | |
max_delay | interval | ||
repeat_delay | interval | ||
usr_field | text | ||
config.usr_setting_type.name | opt_in_setting | text | |
delay_field | text | UNIQUE#1 | |
group_field | text | ||
template | text | ||
granularity | text | ||
context_usr_path | text | ||
context_library_path | text | ||
context_bib_path | text | ||
context_item_path | text | ||
message_template | text | ||
message_usr_path | text | ||
message_library_path | text | ||
message_title | text | ||
retention_interval | interval |
Tables referencing this one via Foreign Key Constraints:
Table: action_trigger.event_output
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
create_time | timestamp with time zone | NOT NULL DEFAULT now() | |
is_error | boolean | NOT NULL DEFAULT false | |
data | text | NOT NULL | |
locale | text |
Tables referencing this one via Foreign Key Constraints:
Table: action_trigger.event_params
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
action_trigger.event_definition.id | event_def | integer | UNIQUE#1 NOT NULL |
param | text | UNIQUE#1 NOT NULL | |
value | text | NOT NULL |
Table: action_trigger.hook
F-Key | Name | Type | Description |
---|---|---|---|
key | text | PRIMARY KEY | |
core_type | text | NOT NULL | |
description | text | ||
passive | boolean | NOT NULL DEFAULT false |
Tables referencing this one via Foreign Key Constraints:
Table: action_trigger.reactor
F-Key | Name | Type | Description |
---|---|---|---|
module | text | PRIMARY KEY | |
description | text |
Tables referencing this one via Foreign Key Constraints:
Table: action_trigger.validator
F-Key | Name | Type | Description |
---|---|---|---|
module | text | PRIMARY KEY | |
description | text |
Tables referencing this one via Foreign Key Constraints:
Function: action_trigger.check_valid_retention_interval()
Returns: trigger
Language: PLPGSQL
BEGIN /* * 1. Retention intervals are always allowed on active hooks. * 2. On passive hooks, retention intervals are only allowed * when the event definition has a max_delay value and the * retention_interval value is greater than the difference * beteween the delay and max_delay values. */ PERFORM TRUE FROM action_trigger.hook WHERE key = NEW.hook AND NOT passive; IF FOUND THEN RETURN NEW; END IF; IF NEW.max_delay IS NOT NULL THEN IF EXTRACT(EPOCH FROM NEW.retention_interval) > ABS(EXTRACT(EPOCH FROM (NEW.max_delay - NEW.delay))) THEN RETURN NEW; -- all good ELSE RAISE EXCEPTION 'retention_interval is too short'; END IF; ELSE RAISE EXCEPTION 'retention_interval requires max_delay'; END IF; END;
Function: action_trigger.purge_events()
Returns: void
Language: PLPGSQL
/** * Deleting expired events without simultaneously deleting their outputs * creates orphaned outputs. Deleting their outputs and all of the events * linking back to them, plus any outputs those events link to is messy and * inefficient. It's simpler to handle them in 2 sweeping steps. * * 1. Delete expired events. * 2. Delete orphaned event outputs. * * This has the added benefit of removing outputs that may have been * orphaned by some other process. Such outputs are not usuable by * the system. * * This does not guarantee that all events within an event group are * purged at the same time. In such cases, the remaining events will * be purged with the next instance of the purge (or soon thereafter). * This is another nod toward efficiency over completeness of old * data that's circling the bit bucket anyway. */ BEGIN DELETE FROM action_trigger.event WHERE id IN ( SELECT evt.id FROM action_trigger.event evt JOIN action_trigger.event_definition def ON (def.id = evt.event_def) WHERE def.retention_interval IS NOT NULL AND evt.state <> 'pending' AND evt.update_time < (NOW() - def.retention_interval) ); WITH linked_outputs AS ( SELECT templates.id AS id FROM ( SELECT DISTINCT(template_output) AS id FROM action_trigger.event WHERE template_output IS NOT NULL UNION SELECT DISTINCT(error_output) AS id FROM action_trigger.event WHERE error_output IS NOT NULL UNION SELECT DISTINCT(async_output) AS id FROM action_trigger.event WHERE async_output IS NOT NULL ) templates ) DELETE FROM action_trigger.event_output WHERE id NOT IN (SELECT id FROM linked_outputs); END;
Schema actor
Holds all tables pertaining to users and libraries (org units).
Table: actor.address_alert
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | owner | integer | NOT NULL |
active | boolean | NOT NULL DEFAULT true | |
match_all | boolean | NOT NULL DEFAULT true | |
alert_message | text | NOT NULL | |
street1 | text | ||
street2 | text | ||
city | text | ||
county | text | ||
state | text | ||
country | text | ||
post_code | text | ||
mailing_address | boolean | NOT NULL DEFAULT false | |
billing_address | boolean | NOT NULL DEFAULT false |
Table: actor.card
Library Cards Each User has one or more library cards. The current "main" card is linked to here from the actor.usr table, and it is up to the consortium policy whether more than one card can be active for any one user at a given time.
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.usr.id | usr | integer | NOT NULL |
barcode | text | UNIQUE NOT NULL | |
active | boolean | NOT NULL DEFAULT true |
Table: actor.copy_alert_suppress
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | org | integer | NOT NULL |
config.copy_alert_type.id | alert_type | integer | NOT NULL |
Table: actor.hours_of_operation
When does this org_unit usually open and close? (Variations are expressed in the actor.org_unit_closed table.)
F-Key | Name | Type | Description |
---|---|---|---|
actor.org_unit.id | id | integer | PRIMARY KEY |
dow_0_open | time without time zone |
NOT NULL
DEFAULT '09:00:00'::time without time zone
When does this org_unit open on Monday? |
|
dow_0_close | time without time zone |
NOT NULL
DEFAULT '17:00:00'::time without time zone
When does this org_unit close on Monday? |
|
dow_0_note | text | ||
dow_1_open | time without time zone |
NOT NULL
DEFAULT '09:00:00'::time without time zone
When does this org_unit open on Tuesday? |
|
dow_1_close | time without time zone |
NOT NULL
DEFAULT '17:00:00'::time without time zone
When does this org_unit close on Tuesday? |
|
dow_1_note | text | ||
dow_2_open | time without time zone |
NOT NULL
DEFAULT '09:00:00'::time without time zone
When does this org_unit open on Wednesday? |
|
dow_2_close | time without time zone |
NOT NULL
DEFAULT '17:00:00'::time without time zone
When does this org_unit close on Wednesday? |
|
dow_2_note | text | ||
dow_3_open | time without time zone |
NOT NULL
DEFAULT '09:00:00'::time without time zone
When does this org_unit open on Thursday? |
|
dow_3_close | time without time zone |
NOT NULL
DEFAULT '17:00:00'::time without time zone
When does this org_unit close on Thursday? |
|
dow_3_note | text | ||
dow_4_open | time without time zone |
NOT NULL
DEFAULT '09:00:00'::time without time zone
When does this org_unit open on Friday? |
|
dow_4_close | time without time zone |
NOT NULL
DEFAULT '17:00:00'::time without time zone
When does this org_unit close on Friday? |
|
dow_4_note | text | ||
dow_5_open | time without time zone |
NOT NULL
DEFAULT '09:00:00'::time without time zone
When does this org_unit open on Saturday? |
|
dow_5_close | time without time zone |
NOT NULL
DEFAULT '17:00:00'::time without time zone
When does this org_unit close on Saturday? |
|
dow_5_note | text | ||
dow_6_open | time without time zone |
NOT NULL
DEFAULT '09:00:00'::time without time zone
When does this org_unit open on Sunday? |
|
dow_6_close | time without time zone |
NOT NULL
DEFAULT '17:00:00'::time without time zone
When does this org_unit close on Sunday? |
|
dow_6_note | text |
Table: actor.org_address
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
valid | boolean | NOT NULL DEFAULT true | |
address_type | text | NOT NULL DEFAULT 'MAILING'::text | |
actor.org_unit.id | org_unit | integer | NOT NULL |
street1 | text | NOT NULL | |
street2 | text | ||
city | text | NOT NULL | |
county | text | ||
state | text | ||
country | text | NOT NULL | |
post_code | text | NOT NULL | |
san | text | ||
latitude | double precision | ||
longitude | double precision |
Tables referencing this one via Foreign Key Constraints:
actor_org_address_org_unit_idx org_unitTable: actor.org_lasso
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE | |
global | boolean | NOT NULL DEFAULT false |
Tables referencing this one via Foreign Key Constraints:
Table: actor.org_lasso_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_lasso.id | lasso | integer | NOT NULL |
actor.org_unit.id | org_unit | integer | NOT NULL |
Table: actor.org_unit
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | parent_ou | integer | |
actor.org_unit_type.id | ou_type | integer | NOT NULL |
actor.org_address.id | ill_address | integer | |
actor.org_address.id | holds_address | integer | |
actor.org_address.id | mailing_address | integer | |
actor.org_address.id | billing_address | integer | |
shortname | text | UNIQUE NOT NULL | |
name | text | UNIQUE NOT NULL | |
text | |||
phone | text | ||
opac_visible | boolean | NOT NULL DEFAULT true | |
acq.fiscal_calendar.id | fiscal_calendar | integer | NOT NULL DEFAULT 1 |
Tables referencing this one via Foreign Key Constraints:
actor_org_unit_billing_address_idx billing_address actor_org_unit_holds_address_idx holds_address actor_org_unit_ill_address_idx ill_address actor_org_unit_mailing_address_idx mailing_address actor_org_unit_ou_type_idx ou_type actor_org_unit_parent_ou_idx parent_ouTable: actor.org_unit_closed
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | org_unit | integer | NOT NULL |
close_start | timestamp with time zone | NOT NULL | |
close_end | timestamp with time zone | NOT NULL | |
full_day | boolean | NOT NULL DEFAULT false | |
multi_day | boolean | NOT NULL DEFAULT false | |
reason | text | ||
action.emergency_closing.id | emergency_closing | integer |
Table: actor.org_unit_custom_tree
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
active | boolean | DEFAULT false | |
purpose | actor.org_unit_custom_tree_purpose | UNIQUE NOT NULL DEFAULT 'opac'::actor.org_unit_custom_tree_purpose |
Tables referencing this one via Foreign Key Constraints:
Table: actor.org_unit_custom_tree_node
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit_custom_tree.id | tree | integer | UNIQUE#1 |
actor.org_unit.id | org_unit | integer | UNIQUE#1 NOT NULL |
actor.org_unit_custom_tree_node.id | parent_node | integer | |
sibling_order | integer | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: actor.org_unit_proximity
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
from_org | integer | ||
to_org | integer | ||
prox | integer |
Table: actor.org_unit_proximity_adjustment
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | item_circ_lib | integer | |
actor.org_unit.id | item_owning_lib | integer | |
asset.copy_location.id | copy_location | integer | |
actor.org_unit.id | hold_pickup_lib | integer | |
actor.org_unit.id | hold_request_lib | integer | |
pos | integer | NOT NULL | |
absolute_adjustment | boolean | NOT NULL DEFAULT false | |
prox_adjustment | numeric | ||
config.circ_modifier.code | circ_mod | text |
Name | Constraint |
---|---|
prox_adj_criterium | CHECK ((COALESCE((item_circ_lib)::text, (item_owning_lib)::text, (copy_location)::text, (hold_pickup_lib)::text, (hold_request_lib)::text, circ_mod) IS NOT NULL)) |
Table: actor.org_unit_setting
Org Unit settings This table contains any arbitrary settings that a client program would like to save for an org unit.
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
actor.org_unit.id | org_unit | integer | UNIQUE#1 NOT NULL |
config.org_unit_setting_type.name | name | text | UNIQUE#1 NOT NULL |
value | text | NOT NULL |
Name | Constraint |
---|---|
aous_must_be_json | CHECK (is_json(value)) |
Table: actor.org_unit_type
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | NOT NULL | |
opac_label | text | NOT NULL | |
depth | integer | NOT NULL | |
actor.org_unit_type.id | parent | integer | |
can_have_vols | boolean | NOT NULL DEFAULT true | |
can_have_users | boolean | NOT NULL DEFAULT true |
Tables referencing this one via Foreign Key Constraints:
actor_org_unit_type_parent_idx parentTable: actor.passwd
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.usr.id | usr | integer | UNIQUE#1 NOT NULL |
salt | text | ||
passwd | text | NOT NULL | |
actor.passwd_type.code | passwd_type | text | UNIQUE#1 NOT NULL |
create_date | timestamp with time zone | NOT NULL DEFAULT now() | |
edit_date | timestamp with time zone | NOT NULL DEFAULT now() |
Table: actor.passwd_type
F-Key | Name | Type | Description |
---|---|---|---|
code | text | PRIMARY KEY | |
name | text | UNIQUE NOT NULL | |
login | boolean | NOT NULL DEFAULT false | |
regex | text | ||
crypt_algo | text | ||
iter_count | integer |
Name | Constraint |
---|---|
passwd_type_iter_count_check | CHECK (((iter_count IS NULL) OR (iter_count > 0))) |
Tables referencing this one via Foreign Key Constraints:
Table: actor.search_filter_group
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | owner | integer | UNIQUE#2 UNIQUE#1 NOT NULL |
code | text | UNIQUE#2 NOT NULL | |
label | text | UNIQUE#1 NOT NULL | |
create_date | timestamp with time zone | NOT NULL DEFAULT now() |
Tables referencing this one via Foreign Key Constraints:
Table: actor.search_filter_group_entry
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.search_filter_group.id | grp | integer | UNIQUE#1 NOT NULL |
pos | integer | NOT NULL | |
actor.search_query.id | query | integer | UNIQUE#1 NOT NULL |
Table: actor.search_query
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
label | text | NOT NULL | |
query_text | text | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: actor.stat_cat
User Statistical Catagories Local data collected about Users is placed into a Statistical Catagory. Here's where those catagories are defined.
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | owner | integer | UNIQUE#1 NOT NULL |
name | text | UNIQUE#1 NOT NULL | |
opac_visible | boolean | NOT NULL DEFAULT false | |
usr_summary | boolean | NOT NULL DEFAULT false | |
actor.stat_cat_sip_fields.field | sip_field | character(2) | |
sip_format | text | ||
checkout_archive | boolean | NOT NULL DEFAULT false | |
required | boolean | NOT NULL DEFAULT false | |
allow_freetext | boolean | NOT NULL DEFAULT true |
Tables referencing this one via Foreign Key Constraints:
Table: actor.stat_cat_entry
User Statistical Catagory Entries Local data collected about Users is placed into a Statistical Catagory. Each library can create entries into any of its own stat_cats, its ancestors' stat_cats, or its descendants' stat_cats.
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.stat_cat.id | stat_cat | integer | UNIQUE#1 NOT NULL |
actor.org_unit.id | owner | integer | UNIQUE#1 NOT NULL |
value | text | UNIQUE#1 NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: actor.stat_cat_entry_default
User Statistical Category Default Entry A library may choose one of the stat_cat entries to be the default entry.
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.stat_cat_entry.id | stat_cat_entry | integer | NOT NULL |
actor.stat_cat.id | stat_cat | integer | UNIQUE#1 NOT NULL |
actor.org_unit.id | owner | integer | UNIQUE#1 NOT NULL |
Table: actor.stat_cat_entry_usr_map
Statistical Catagory Entry to User map Records the stat_cat entries for each user.
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
stat_cat_entry | text | NOT NULL | |
actor.stat_cat.id | stat_cat | integer | UNIQUE#1 NOT NULL |
actor.usr.id | target_usr | integer | UNIQUE#1 NOT NULL |
Table: actor.stat_cat_sip_fields
Actor Statistical Category SIP Fields Contains the list of valid SIP Field identifiers for Statistical Categories.
F-Key | Name | Type | Description |
---|---|---|---|
field | character(2) | PRIMARY KEY | |
name | text | NOT NULL | |
one_only | boolean | NOT NULL DEFAULT false |
Tables referencing this one via Foreign Key Constraints:
Table: actor.toolbar
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
actor.workstation.id | ws | integer | |
actor.org_unit.id | org | integer | |
actor.usr.id | usr | integer | |
label | text | NOT NULL | |
layout | text | NOT NULL |
Name | Constraint |
---|---|
layout_must_be_json | CHECK (is_json(layout)) |
only_one_type | CHECK ((((ws IS NOT NULL) AND (COALESCE(org, usr) IS NULL)) OR ((org IS NOT NULL) AND (COALESCE(ws, usr) IS NULL)) OR ((usr IS NOT NULL) AND (COALESCE(org, ws) IS NULL)))) |
Table: actor.usr
User objects This table contains the core User objects that describe both staff members and patrons. The difference between the two types of users is based on the user's permissions.
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
card | integer | UNIQUE | |
permission.grp_tree.id | profile | integer | NOT NULL |
usrname | text | UNIQUE NOT NULL | |
text | |||
passwd | text | NOT NULL | |
config.standing.id | standing | integer | NOT NULL DEFAULT 1 |
config.identification_type.id | ident_type | integer | NOT NULL |
ident_value | text | ||
config.identification_type.id | ident_type2 | integer | |
ident_value2 | text | ||
config.net_access_level.id | net_access_level | integer | NOT NULL DEFAULT 1 |
photo_url | text | ||
prefix | text | ||
first_given_name | text | NOT NULL | |
second_given_name | text | ||
family_name | text | NOT NULL | |
suffix | text | ||
guardian | text | ||
pref_prefix | text | ||
pref_first_given_name | text | ||
pref_second_given_name | text | ||
pref_family_name | text | ||
pref_suffix | text | ||
name_keywords | text | ||
name_kw_tsvector | tsvector | ||
alias | text | ||
day_phone | text | ||
evening_phone | text | ||
other_phone | text | ||
actor.usr_address.id | mailing_address | integer | |
actor.usr_address.id | billing_address | integer | |
actor.org_unit.id | home_ou | integer | NOT NULL |
dob | date | ||
active | boolean | NOT NULL DEFAULT true | |
master_account | boolean | NOT NULL DEFAULT false | |
super_user | boolean | NOT NULL DEFAULT false | |
barred | boolean | NOT NULL DEFAULT false | |
deleted | boolean | NOT NULL DEFAULT false | |
juvenile | boolean | NOT NULL DEFAULT false | |
usrgroup | serial | NOT NULL | |
claims_returned_count | integer | NOT NULL | |
credit_forward_balance | numeric(6,2) | NOT NULL DEFAULT 0.00 | |
last_xact_id | text | NOT NULL DEFAULT 'none'::text | |
create_date | timestamp with time zone | NOT NULL DEFAULT now() | |
expire_date | timestamp with time zone | NOT NULL DEFAULT (now() + '3 years'::interval) | |
claims_never_checked_out_count | integer | NOT NULL | |
last_update_time | timestamp with time zone | ||
config.i18n_locale.code | locale | text |
Tables referencing this one via Foreign Key Constraints:
actor_usr_billing_address_idx billing_address actor_usr_day_phone_idx lowercase(day_phone) actor_usr_day_phone_idx_numeric lowercase(regexp_replace(day_phone, '[^0-9]'::text, ''::text, 'g'::text)) actor_usr_email_idx lowercase(email) actor_usr_evening_phone_idx lowercase(evening_phone) actor_usr_evening_phone_idx_numeric lowercase(regexp_replace(evening_phone, '[^0-9]'::text, ''::text, 'g'::text)) actor_usr_family_name_idx lowercase(family_name) actor_usr_family_name_unaccent_idx unaccent_and_squash(family_name) actor_usr_first_given_name_idx lowercase(first_given_name) actor_usr_first_given_name_unaccent_idx unaccent_and_squash(first_given_name) actor_usr_guardian_idx lowercase(guardian) actor_usr_guardian_unaccent_idx unaccent_and_squash(guardian) actor_usr_home_ou_idx home_ou actor_usr_ident_value2_idx lowercase(ident_value2) actor_usr_ident_value_idx lowercase(ident_value) actor_usr_mailing_address_idx mailing_address actor_usr_other_phone_idx lowercase(other_phone) actor_usr_other_phone_idx_numeric lowercase(regexp_replace(other_phone, '[^0-9]'::text, ''::text, 'g'::text)) actor_usr_pref_family_name_idx lowercase(pref_family_name) actor_usr_pref_family_name_unaccent_idx unaccent_and_squash(pref_family_name) actor_usr_pref_first_given_name_idx lowercase(pref_first_given_name) actor_usr_pref_first_given_name_unaccent_idx unaccent_and_squash(pref_first_given_name) actor_usr_pref_second_given_name_idx lowercase(pref_second_given_name) actor_usr_pref_second_given_name_unaccent_idx unaccent_and_squash(pref_second_given_name) actor_usr_second_given_name_idx lowercase(second_given_name) actor_usr_second_given_name_unaccent_idx unaccent_and_squash(second_given_name) actor_usr_usrgroup_idx usrgroup actor_usr_usrname_idx lowercase(usrname) actor_usr_usrname_unaccent_idx unaccent_and_squash(usrname)Table: actor.usr_activity
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
actor.usr.id | usr | integer | |
config.usr_activity_type.id | etype | integer | NOT NULL |
event_time | timestamp with time zone | NOT NULL DEFAULT now() |
Table: actor.usr_address
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
valid | boolean | NOT NULL DEFAULT true | |
within_city_limits | boolean | NOT NULL DEFAULT true | |
address_type | text | NOT NULL DEFAULT 'MAILING'::text | |
actor.usr.id | usr | integer | NOT NULL |
street1 | text | NOT NULL | |
street2 | text | ||
city | text | NOT NULL | |
county | text | ||
state | text | ||
country | text | NOT NULL | |
post_code | text | NOT NULL | |
pending | boolean | NOT NULL DEFAULT false | |
actor.usr_address.id | replaces | integer |
Tables referencing this one via Foreign Key Constraints:
actor_usr_addr_city_idx lowercase(city) actor_usr_addr_post_code_idx lowercase(post_code) actor_usr_addr_state_idx lowercase(state) actor_usr_addr_street1_idx lowercase(street1) actor_usr_addr_street2_idx lowercase(street2) actor_usr_addr_usr_idx usrTable: actor.usr_message
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.usr.id | usr | integer | NOT NULL |
title | text | ||
message | text | NOT NULL | |
create_date | timestamp with time zone | NOT NULL DEFAULT now() | |
deleted | boolean | NOT NULL DEFAULT false | |
read_date | timestamp with time zone | ||
actor.org_unit.id | sending_lib | integer | NOT NULL |
pub | boolean | NOT NULL DEFAULT false | |
stop_date | timestamp with time zone | ||
actor.usr.id | editor | bigint | |
edit_date | timestamp with time zone |
Tables referencing this one via Foreign Key Constraints:
aum_editor editor aum_usr usrView: actor.usr_message_limited
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
usr | integer | ||
title | text | ||
message | text | ||
create_date | timestamp with time zone | ||
deleted | boolean | ||
read_date | timestamp with time zone | ||
sending_lib | integer | ||
pub | boolean | ||
stop_date | timestamp with time zone | ||
editor | bigint | ||
edit_date | timestamp with time zone |
SELECT usr_message.id , usr_message.usr , usr_message.title , usr_message.message , usr_message.create_date , usr_message.deleted , usr_message.read_date , usr_message.sending_lib , usr_message.pub , usr_message.stop_date , usr_message.editor , usr_message.edit_date FROM actor.usr_message WHERE (usr_message.pub AND (NOT usr_message.deleted) );
View: actor.usr_message_penalty
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
ausp_id | integer | ||
aum_id | integer | ||
org_unit | integer | ||
ausp_org_unit | integer | ||
aum_sending_lib | integer | ||
usr | integer | ||
ausp_usr | integer | ||
aum_usr | integer | ||
standing_penalty | integer | ||
staff | integer | ||
create_date | timestamp with time zone | ||
ausp_set_date | timestamp with time zone | ||
aum_create_date | timestamp with time zone | ||
stop_date | timestamp with time zone | ||
ausp_stop_date | timestamp with time zone | ||
aum_stop_date | timestamp with time zone | ||
ausp_usr_message | bigint | ||
title | text | ||
message | text | ||
deleted | boolean | ||
read_date | timestamp with time zone | ||
pub | boolean | ||
editor | bigint | ||
edit_date | timestamp with time zone |
SELECT ausp.id , ausp.id AS ausp_id , aum.id AS aum_id , ausp.org_unit , ausp.org_unit AS ausp_org_unit , aum.sending_lib AS aum_sending_lib , ausp.usr , ausp.usr AS ausp_usr , aum.usr AS aum_usr , ausp.standing_penalty , ausp.staff , ausp.set_date AS create_date , ausp.set_date AS ausp_set_date , aum.create_date AS aum_create_date , ausp.stop_date , ausp.stop_date AS ausp_stop_date , aum.stop_date AS aum_stop_date , ausp.usr_message AS ausp_usr_message , aum.title , aum.message , aum.deleted , aum.read_date , aum.pub , aum.editor , aum.edit_date FROM (actor.usr_standing_penalty ausp LEFT JOIN actor.usr_message aum ON ( (ausp.usr_message = aum.id) ) ) UNION ALL SELECT aum.id , NULL::integer AS ausp_id , aum.id AS aum_id , aum.sending_lib AS org_unit , NULL::integer AS ausp_org_unit , aum.sending_lib AS aum_sending_lib , aum.usr , NULL::integer AS ausp_usr , aum.usr AS aum_usr , NULL::integer AS standing_penalty , NULL::integer AS staff , aum.create_date , NULL::timestamp with time zone AS ausp_set_date , aum.create_date AS aum_create_date , aum.stop_date , NULL::timestamp with time zone AS ausp_stop_date , aum.stop_date AS aum_stop_date , NULL::integer AS ausp_usr_message , aum.title , aum.message , aum.deleted , aum.read_date , aum.pub , aum.editor , aum.edit_date FROM (actor.usr_message aum LEFT JOIN actor.usr_standing_penalty ausp ON ( (ausp.usr_message = aum.id) ) ) WHERE ( (NOT aum.deleted) AND (ausp.id IS NULL) );
Table: actor.usr_org_unit_opt_in
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | org_unit | integer | UNIQUE#1 NOT NULL |
actor.usr.id | usr | integer | UNIQUE#1 NOT NULL |
actor.usr.id | staff | integer | NOT NULL |
opt_in_ts | timestamp with time zone | NOT NULL DEFAULT now() | |
actor.workstation.id | opt_in_ws | integer | NOT NULL |
Table: actor.usr_password_reset
Self-serve password reset requests
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
uuid | text | NOT NULL | |
actor.usr.id | usr | bigint | NOT NULL |
request_time | timestamp with time zone | NOT NULL DEFAULT now() | |
has_been_reset | boolean | NOT NULL DEFAULT false |
Table: actor.usr_privacy_waiver
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
actor.usr.id | usr | bigint | NOT NULL |
name | text | NOT NULL | |
place_holds | boolean | DEFAULT false | |
pickup_holds | boolean | DEFAULT false | |
view_history | boolean | DEFAULT false | |
checkout_items | boolean | DEFAULT false |
Table: actor.usr_saved_search
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.usr.id | owner | integer | UNIQUE#1 NOT NULL |
name | text | UNIQUE#1 NOT NULL | |
create_date | timestamp with time zone | NOT NULL DEFAULT now() | |
query_text | text | NOT NULL | |
query_type | text | NOT NULL DEFAULT 'URL'::text | |
target | text | NOT NULL |
Name | Constraint |
---|---|
valid_query_text | CHECK ((query_type = 'URL'::text)) |
valid_target | CHECK ((target = ANY (ARRAY['record'::text, 'metarecord'::text, 'callnumber'::text]))) |
Table: actor.usr_setting
User settings This table contains any arbitrary settings that a client program would like to save for a user.
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
actor.usr.id | usr | integer | UNIQUE#1 NOT NULL |
config.usr_setting_type.name | name | text | UNIQUE#1 NOT NULL |
value | text | NOT NULL |
Table: actor.usr_standing_penalty
User standing penalties
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | org_unit | integer | NOT NULL |
actor.usr.id | usr | integer | NOT NULL |
config.standing_penalty.id | standing_penalty | integer | NOT NULL |
actor.usr.id | staff | integer | |
set_date | timestamp with time zone | DEFAULT now() | |
stop_date | timestamp with time zone | ||
actor.usr_message.id | usr_message | bigint |
Table: actor.workstation
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE NOT NULL | |
actor.org_unit.id | owning_lib | integer | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: actor.workstation_setting
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.workstation.id | workstation | integer | UNIQUE#1 NOT NULL |
config.workstation_setting_type.name | name | text | UNIQUE#1 NOT NULL |
value | json | NOT NULL |
Function: actor.address_alert_matches(billing_address integer, mailing_address text, post_code text, country text, state text, county text, city text, street2 text, street1 boolean, org_unit boolean)
Returns: SET OF address_alert
Language: SQL
SELECT * FROM actor.address_alert WHERE active AND owner IN (SELECT id FROM actor.org_unit_ancestors($1)) AND ( (NOT mailing_address AND NOT billing_address) OR (mailing_address AND $9) OR (billing_address AND $10) ) AND ( ( match_all AND COALESCE($2, '') ~* COALESCE(street1, '.*') AND COALESCE($3, '') ~* COALESCE(street2, '.*') AND COALESCE($4, '') ~* COALESCE(city, '.*') AND COALESCE($5, '') ~* COALESCE(county, '.*') AND COALESCE($6, '') ~* COALESCE(state, '.*') AND COALESCE($7, '') ~* COALESCE(country, '.*') AND COALESCE($8, '') ~* COALESCE(post_code, '.*') ) OR ( NOT match_all AND ( $2 ~* street1 OR $3 ~* street2 OR $4 ~* city OR $5 ~* county OR $6 ~* state OR $7 ~* country OR $8 ~* post_code ) ) ) ORDER BY actor.org_unit_proximity(owner, $1)
Function: actor.approve_pending_address(pending_id integer)
Returns: bigint
Language: PLPGSQL
Replaces an address with a pending address. This is done by giving the pending address the ID of the old address. The replaced address is retained with -id.
DECLARE old_id INT; BEGIN SELECT INTO old_id replaces FROM actor.usr_address where id = pending_id; IF old_id IS NULL THEN UPDATE actor.usr_address SET pending = 'f' WHERE id = pending_id; RETURN pending_id; END IF; -- address replaces an existing address DELETE FROM actor.usr_address WHERE id = -old_id; UPDATE actor.usr_address SET id = -id WHERE id = old_id; UPDATE actor.usr_address SET replaces = NULL, id = old_id, pending = 'f' WHERE id = pending_id; RETURN old_id; END
Function: actor.au_updated()
Returns: trigger
Language: PLPGSQL
BEGIN NEW.last_update_time := now(); RETURN NEW; END;
Function: actor.calculate_system_penalties(context_org integer, match_user integer)
Returns: SET OF usr_standing_penalty
Language: PLPGSQL
DECLARE user_object actor.usr%ROWTYPE; new_sp_row actor.usr_standing_penalty%ROWTYPE; existing_sp_row actor.usr_standing_penalty%ROWTYPE; collections_fines permission.grp_penalty_threshold%ROWTYPE; max_fines permission.grp_penalty_threshold%ROWTYPE; max_overdue permission.grp_penalty_threshold%ROWTYPE; max_items_out permission.grp_penalty_threshold%ROWTYPE; max_lost permission.grp_penalty_threshold%ROWTYPE; max_longoverdue permission.grp_penalty_threshold%ROWTYPE; tmp_grp INT; items_overdue INT; items_out INT; items_lost INT; items_longoverdue INT; context_org_list INT[]; current_fines NUMERIC(8,2) := 0.0; tmp_fines NUMERIC(8,2); tmp_groc RECORD; tmp_circ RECORD; tmp_org actor.org_unit%ROWTYPE; tmp_penalty config.standing_penalty%ROWTYPE; tmp_depth INTEGER; BEGIN SELECT INTO user_object * FROM actor.usr WHERE id = match_user; -- Max fines SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org; -- Fail if the user has a high fine balance LOOP tmp_grp := user_object.profile; LOOP SELECT * INTO max_fines FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 1 AND org_unit = tmp_org.id; IF max_fines.threshold IS NULL THEN SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp; ELSE EXIT; END IF; IF tmp_grp IS NULL THEN EXIT; END IF; END LOOP; IF max_fines.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN EXIT; END IF; SELECT * INTO tmp_org FROM actor.org_unit WHERE id = tmp_org.parent_ou; END LOOP; IF max_fines.threshold IS NOT NULL THEN RETURN QUERY SELECT * FROM actor.usr_standing_penalty WHERE usr = match_user AND org_unit = max_fines.org_unit AND (stop_date IS NULL or stop_date > NOW()) AND standing_penalty = 1; SELECT INTO context_org_list ARRAY_AGG(id) FROM actor.org_unit_full_path( max_fines.org_unit ); SELECT SUM(f.balance_owed) INTO current_fines FROM money.materialized_billable_xact_summary f JOIN ( SELECT r.id FROM booking.reservation r WHERE r.usr = match_user AND r.pickup_lib IN (SELECT * FROM unnest(context_org_list)) AND xact_finish IS NULL UNION ALL SELECT g.id FROM money.grocery g WHERE g.usr = match_user AND g.billing_location IN (SELECT * FROM unnest(context_org_list)) AND xact_finish IS NULL UNION ALL SELECT circ.id FROM action.circulation circ WHERE circ.usr = match_user AND circ.circ_lib IN (SELECT * FROM unnest(context_org_list)) AND xact_finish IS NULL ) l USING (id); IF current_fines >= max_fines.threshold THEN new_sp_row.usr := match_user; new_sp_row.org_unit := max_fines.org_unit; new_sp_row.standing_penalty := 1; RETURN NEXT new_sp_row; END IF; END IF; -- Start over for max overdue SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org; -- Fail if the user has too many overdue items LOOP tmp_grp := user_object.profile; LOOP SELECT * INTO max_overdue FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 2 AND org_unit = tmp_org.id; IF max_overdue.threshold IS NULL THEN SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp; ELSE EXIT; END IF; IF tmp_grp IS NULL THEN EXIT; END IF; END LOOP; IF max_overdue.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN EXIT; END IF; SELECT INTO tmp_org * FROM actor.org_unit WHERE id = tmp_org.parent_ou; END LOOP; IF max_overdue.threshold IS NOT NULL THEN RETURN QUERY SELECT * FROM actor.usr_standing_penalty WHERE usr = match_user AND org_unit = max_overdue.org_unit AND (stop_date IS NULL or stop_date > NOW()) AND standing_penalty = 2; SELECT INTO items_overdue COUNT(*) FROM action.circulation circ JOIN actor.org_unit_full_path( max_overdue.org_unit ) fp ON (circ.circ_lib = fp.id) WHERE circ.usr = match_user AND circ.checkin_time IS NULL AND circ.due_date < NOW() AND (circ.stop_fines = 'MAXFINES' OR circ.stop_fines IS NULL); IF items_overdue >= max_overdue.threshold::INT THEN new_sp_row.usr := match_user; new_sp_row.org_unit := max_overdue.org_unit; new_sp_row.standing_penalty := 2; RETURN NEXT new_sp_row; END IF; END IF; -- Start over for max out SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org; -- Fail if the user has too many checked out items LOOP tmp_grp := user_object.profile; LOOP SELECT * INTO max_items_out FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 3 AND org_unit = tmp_org.id; IF max_items_out.threshold IS NULL THEN SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp; ELSE EXIT; END IF; IF tmp_grp IS NULL THEN EXIT; END IF; END LOOP; IF max_items_out.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN EXIT; END IF; SELECT INTO tmp_org * FROM actor.org_unit WHERE id = tmp_org.parent_ou; END LOOP; -- Fail if the user has too many items checked out IF max_items_out.threshold IS NOT NULL THEN RETURN QUERY SELECT * FROM actor.usr_standing_penalty WHERE usr = match_user AND org_unit = max_items_out.org_unit AND (stop_date IS NULL or stop_date > NOW()) AND standing_penalty = 3; SELECT INTO items_out COUNT(*) FROM action.circulation circ JOIN actor.org_unit_full_path( max_items_out.org_unit ) fp ON (circ.circ_lib = fp.id) WHERE circ.usr = match_user AND circ.checkin_time IS NULL AND (circ.stop_fines IN ( SELECT 'MAXFINES'::TEXT UNION ALL SELECT 'LONGOVERDUE'::TEXT UNION ALL SELECT 'LOST'::TEXT WHERE 'true' ILIKE ( SELECT CASE WHEN (SELECT value FROM actor.org_unit_ancestor_setting('circ.tally_lost', circ.circ_lib)) ILIKE 'true' THEN 'true' ELSE 'false' END ) UNION ALL SELECT 'CLAIMSRETURNED'::TEXT WHERE 'false' ILIKE ( SELECT CASE WHEN (SELECT value FROM actor.org_unit_ancestor_setting('circ.do_not_tally_claims_returned', circ.circ_lib)) ILIKE 'true' THEN 'true' ELSE 'false' END ) ) OR circ.stop_fines IS NULL) AND xact_finish IS NULL; IF items_out >= max_items_out.threshold::INT THEN new_sp_row.usr := match_user; new_sp_row.org_unit := max_items_out.org_unit; new_sp_row.standing_penalty := 3; RETURN NEXT new_sp_row; END IF; END IF; -- Start over for max lost SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org; -- Fail if the user has too many lost items LOOP tmp_grp := user_object.profile; LOOP SELECT * INTO max_lost FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 5 AND org_unit = tmp_org.id; IF max_lost.threshold IS NULL THEN SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp; ELSE EXIT; END IF; IF tmp_grp IS NULL THEN EXIT; END IF; END LOOP; IF max_lost.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN EXIT; END IF; SELECT INTO tmp_org * FROM actor.org_unit WHERE id = tmp_org.parent_ou; END LOOP; IF max_lost.threshold IS NOT NULL THEN RETURN QUERY SELECT * FROM actor.usr_standing_penalty WHERE usr = match_user AND org_unit = max_lost.org_unit AND (stop_date IS NULL or stop_date > NOW()) AND standing_penalty = 5; SELECT INTO items_lost COUNT(*) FROM action.circulation circ JOIN actor.org_unit_full_path( max_lost.org_unit ) fp ON (circ.circ_lib = fp.id) WHERE circ.usr = match_user AND circ.checkin_time IS NULL AND (circ.stop_fines = 'LOST') AND xact_finish IS NULL; IF items_lost >= max_lost.threshold::INT AND 0 < max_lost.threshold::INT THEN new_sp_row.usr := match_user; new_sp_row.org_unit := max_lost.org_unit; new_sp_row.standing_penalty := 5; RETURN NEXT new_sp_row; END IF; END IF; -- Start over for max longoverdue SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org; -- Fail if the user has too many longoverdue items LOOP tmp_grp := user_object.profile; LOOP SELECT * INTO max_longoverdue FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 35 AND org_unit = tmp_org.id; IF max_longoverdue.threshold IS NULL THEN SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp; ELSE EXIT; END IF; IF tmp_grp IS NULL THEN EXIT; END IF; END LOOP; IF max_longoverdue.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN EXIT; END IF; SELECT INTO tmp_org * FROM actor.org_unit WHERE id = tmp_org.parent_ou; END LOOP; IF max_longoverdue.threshold IS NOT NULL THEN RETURN QUERY SELECT * FROM actor.usr_standing_penalty WHERE usr = match_user AND org_unit = max_longoverdue.org_unit AND (stop_date IS NULL or stop_date > NOW()) AND standing_penalty = 35; SELECT INTO items_longoverdue COUNT(*) FROM action.circulation circ JOIN actor.org_unit_full_path( max_longoverdue.org_unit ) fp ON (circ.circ_lib = fp.id) WHERE circ.usr = match_user AND circ.checkin_time IS NULL AND (circ.stop_fines = 'LONGOVERDUE') AND xact_finish IS NULL; IF items_longoverdue >= max_longoverdue.threshold::INT AND 0 < max_longoverdue.threshold::INT THEN new_sp_row.usr := match_user; new_sp_row.org_unit := max_longoverdue.org_unit; new_sp_row.standing_penalty := 35; RETURN NEXT new_sp_row; END IF; END IF; -- Start over for collections warning SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org; -- Fail if the user has a collections-level fine balance LOOP tmp_grp := user_object.profile; LOOP SELECT * INTO max_fines FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 4 AND org_unit = tmp_org.id; IF max_fines.threshold IS NULL THEN SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp; ELSE EXIT; END IF; IF tmp_grp IS NULL THEN EXIT; END IF; END LOOP; IF max_fines.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN EXIT; END IF; SELECT * INTO tmp_org FROM actor.org_unit WHERE id = tmp_org.parent_ou; END LOOP; IF max_fines.threshold IS NOT NULL THEN RETURN QUERY SELECT * FROM actor.usr_standing_penalty WHERE usr = match_user AND org_unit = max_fines.org_unit AND (stop_date IS NULL or stop_date > NOW()) AND standing_penalty = 4; SELECT INTO context_org_list ARRAY_AGG(id) FROM actor.org_unit_full_path( max_fines.org_unit ); SELECT SUM(f.balance_owed) INTO current_fines FROM money.materialized_billable_xact_summary f JOIN ( SELECT r.id FROM booking.reservation r WHERE r.usr = match_user AND r.pickup_lib IN (SELECT * FROM unnest(context_org_list)) AND r.xact_finish IS NULL UNION ALL SELECT g.id FROM money.grocery g WHERE g.usr = match_user AND g.billing_location IN (SELECT * FROM unnest(context_org_list)) AND g.xact_finish IS NULL UNION ALL SELECT circ.id FROM action.circulation circ WHERE circ.usr = match_user AND circ.circ_lib IN (SELECT * FROM unnest(context_org_list)) AND circ.xact_finish IS NULL ) l USING (id); IF current_fines >= max_fines.threshold THEN new_sp_row.usr := match_user; new_sp_row.org_unit := max_fines.org_unit; new_sp_row.standing_penalty := 4; RETURN NEXT new_sp_row; END IF; END IF; -- Start over for in collections SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org; -- Remove the in-collections penalty if the user has paid down enough -- This penalty is different, because this code is not responsible for creating -- new in-collections penalties, only for removing them LOOP tmp_grp := user_object.profile; LOOP SELECT * INTO max_fines FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 30 AND org_unit = tmp_org.id; IF max_fines.threshold IS NULL THEN SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp; ELSE EXIT; END IF; IF tmp_grp IS NULL THEN EXIT; END IF; END LOOP; IF max_fines.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN EXIT; END IF; SELECT * INTO tmp_org FROM actor.org_unit WHERE id = tmp_org.parent_ou; END LOOP; IF max_fines.threshold IS NOT NULL THEN SELECT INTO context_org_list ARRAY_AGG(id) FROM actor.org_unit_full_path( max_fines.org_unit ); -- first, see if the user had paid down to the threshold SELECT SUM(f.balance_owed) INTO current_fines FROM money.materialized_billable_xact_summary f JOIN ( SELECT r.id FROM booking.reservation r WHERE r.usr = match_user AND r.pickup_lib IN (SELECT * FROM unnest(context_org_list)) AND r.xact_finish IS NULL UNION ALL SELECT g.id FROM money.grocery g WHERE g.usr = match_user AND g.billing_location IN (SELECT * FROM unnest(context_org_list)) AND g.xact_finish IS NULL UNION ALL SELECT circ.id FROM action.circulation circ WHERE circ.usr = match_user AND circ.circ_lib IN (SELECT * FROM unnest(context_org_list)) AND circ.xact_finish IS NULL ) l USING (id); IF current_fines IS NULL OR current_fines <= max_fines.threshold THEN -- patron has paid down enough SELECT INTO tmp_penalty * FROM config.standing_penalty WHERE id = 30; IF tmp_penalty.org_depth IS NOT NULL THEN -- since this code is not responsible for applying the penalty, it can't -- guarantee the current context org will match the org at which the penalty --- was applied. search up the org tree until we hit the configured penalty depth SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org; SELECT INTO tmp_depth depth FROM actor.org_unit_type WHERE id = tmp_org.ou_type; WHILE tmp_depth >= tmp_penalty.org_depth LOOP RETURN QUERY SELECT * FROM actor.usr_standing_penalty WHERE usr = match_user AND org_unit = tmp_org.id AND (stop_date IS NULL or stop_date > NOW()) AND standing_penalty = 30; IF tmp_org.parent_ou IS NULL THEN EXIT; END IF; SELECT * INTO tmp_org FROM actor.org_unit WHERE id = tmp_org.parent_ou; SELECT INTO tmp_depth depth FROM actor.org_unit_type WHERE id = tmp_org.ou_type; END LOOP; ELSE -- no penalty depth is defined, look for exact matches RETURN QUERY SELECT * FROM actor.usr_standing_penalty WHERE usr = match_user AND org_unit = max_fines.org_unit AND (stop_date IS NULL or stop_date > NOW()) AND standing_penalty = 30; END IF; END IF; END IF; RETURN; END;
Function: actor.change_password(pw_type integer, new_pw text, user_id text)
Returns: void
Language: PLPGSQL
Allows setting a salted password for a user by passing actor.usr id and the text of the password.
DECLARE new_salt TEXT; BEGIN SELECT actor.create_salt(pw_type) INTO new_salt; IF pw_type = 'main' THEN -- Only 'main' passwords are required to have -- the extra layer of MD5 hashing. PERFORM actor.set_passwd( user_id, pw_type, md5(new_salt || md5(new_pw)), new_salt ); ELSE PERFORM actor.set_passwd(user_id, pw_type, new_pw, new_salt); END IF; END;
Function: actor.create_salt(pw_type text)
Returns: text
Language: PLPGSQL
DECLARE type_row actor.passwd_type%ROWTYPE; BEGIN /* Returns a new salt based on the passwd_type encryption settings. * Returns NULL If the password type is not crypt()'ed. */ SELECT INTO type_row * FROM actor.passwd_type WHERE code = pw_type; IF NOT FOUND THEN RETURN EXCEPTION 'No such password type: %', pw_type; END IF; IF type_row.iter_count IS NULL THEN -- This password type is unsalted. That's OK. RETURN NULL; END IF; RETURN gen_salt(type_row.crypt_algo, type_row.iter_count); END;
Function: actor.crypt_pw_insert()
Returns: trigger
Language: PLPGSQL
BEGIN NEW.passwd = MD5( NEW.passwd ); RETURN NEW; END;
Function: actor.crypt_pw_update()
Returns: trigger
Language: PLPGSQL
BEGIN IF NEW.passwd <> OLD.passwd THEN NEW.passwd = MD5( NEW.passwd ); END IF; RETURN NEW; END;
Function: actor.get_cascade_setting(workstation_id text, user_id integer, org_id integer, setting_name integer)
Returns: cascade_setting_summary
Language: PLPGSQL
DECLARE setting_value JSON; summary actor.cascade_setting_summary; org_setting_type config.org_unit_setting_type%ROWTYPE; BEGIN summary.name := setting_name; -- Collect the org setting type status first in case we exit early. -- The existance of an org setting type is not considered -- privileged information. SELECT INTO org_setting_type * FROM config.org_unit_setting_type WHERE name = setting_name; IF FOUND THEN summary.has_org_setting := TRUE; ELSE summary.has_org_setting := FALSE; END IF; -- User and workstation settings have the same priority. -- Start with user settings since that's the simplest code path. -- The workstation_id is ignored if no user_id is provided. IF user_id IS NOT NULL THEN SELECT INTO summary.value value FROM actor.usr_setting WHERE usr = user_id AND name = setting_name; IF FOUND THEN -- if we have a value, we have a setting type summary.has_user_setting := TRUE; IF workstation_id IS NOT NULL THEN -- Only inform the caller about the workstation -- setting type disposition when a workstation id is -- provided. Otherwise, it's NULL to indicate UNKNOWN. summary.has_workstation_setting := FALSE; END IF; RETURN summary; END IF; -- no user setting value, but a setting type may exist SELECT INTO summary.has_user_setting EXISTS ( SELECT TRUE FROM config.usr_setting_type WHERE name = setting_name ); IF workstation_id IS NOT NULL THEN IF NOT summary.has_user_setting THEN -- A workstation setting type may only exist when a user -- setting type does not. SELECT INTO summary.value value FROM actor.workstation_setting WHERE workstation = workstation_id AND name = setting_name; IF FOUND THEN -- if we have a value, we have a setting type summary.has_workstation_setting := TRUE; RETURN summary; END IF; -- no value, but a setting type may exist SELECT INTO summary.has_workstation_setting EXISTS ( SELECT TRUE FROM config.workstation_setting_type WHERE name = setting_name ); END IF; -- Finally make use of the workstation to determine the org -- unit if none is provided. IF org_id IS NULL AND summary.has_org_setting THEN SELECT INTO org_id owning_lib FROM actor.workstation WHERE id = workstation_id; END IF; END IF; END IF; -- Some org unit settings are protected by a view permission. -- First see if we have any data that needs protecting, then -- check the permission if needed. IF NOT summary.has_org_setting THEN RETURN summary; END IF; -- avoid putting the value into the summary until we confirm -- the value should be visible to the caller. SELECT INTO setting_value value FROM actor.org_unit_ancestor_setting(setting_name, org_id); IF NOT FOUND THEN -- No value found -- perm check is irrelevant. RETURN summary; END IF; IF org_setting_type.view_perm IS NOT NULL THEN IF user_id IS NULL THEN RAISE NOTICE 'Perm check required but no user_id provided'; RETURN summary; END IF; IF NOT permission.usr_has_perm( user_id, (SELECT code FROM permission.perm_list WHERE id = org_setting_type.view_perm), org_id) THEN RAISE NOTICE 'Perm check failed for user % on %', user_id, org_setting_type.view_perm; RETURN summary; END IF; END IF; -- Perm check succeeded or was not necessary. summary.value := setting_value; RETURN summary; END;
Function: actor.get_cascade_setting_batch(workstation_id text[], user_id integer, org_id integer, setting_names integer)
Returns: SET OF cascade_setting_summary
Language: PLPGSQL
-- Returns a row per setting matching the setting name order. If no -- value is applied, NULL is returned to retain name-response ordering. DECLARE setting_name TEXT; summary actor.cascade_setting_summary; BEGIN FOREACH setting_name IN ARRAY setting_names LOOP SELECT INTO summary * FROM actor.get_cascade_setting( setting_Name, org_id, user_id, workstation_id); RETURN NEXT summary; END LOOP; END;
Function: actor.get_salt(pw_type integer, pw_usr text)
Returns: text
Language: PLPGSQL
DECLARE pw_salt TEXT; type_row actor.passwd_type%ROWTYPE; BEGIN /* Returns the salt for the requested user + type. If the password * type of "main" is requested and no password exists in actor.passwd, * the user's existing password is migrated and the new salt is returned. * Returns NULL if the password type is not crypt'ed (iter_count is NULL). */ SELECT INTO pw_salt salt FROM actor.passwd WHERE usr = pw_usr AND passwd_type = pw_type; IF FOUND THEN RETURN pw_salt; END IF; IF pw_type = 'main' THEN -- Main password has not yet been migrated. -- Do it now and return the newly created salt. RETURN actor.migrate_passwd(pw_usr); END IF; -- We have no salt to return. actor.create_salt() needed. RETURN NULL; END;
Function: actor.insert_usr_activity(ehow integer, ewhat text, ewho text, usr text)
Returns: SET OF usr_activity
Language: PLPGSQL
DECLARE new_row actor.usr_activity%ROWTYPE; BEGIN SELECT id INTO new_row.etype FROM actor.usr_activity_get_type(ewho, ewhat, ehow); IF FOUND THEN new_row.usr := usr; INSERT INTO actor.usr_activity (usr, etype) VALUES (usr, new_row.etype) RETURNING * INTO new_row; RETURN NEXT new_row; END IF; END;
Function: actor.migrate_passwd(pw_usr integer)
Returns: text
Language: PLPGSQL
DECLARE pw_salt TEXT; usr_row actor.usr%ROWTYPE; BEGIN /* Migrates legacy actor.usr.passwd value to actor.passwd with * a password type 'main' and returns the new salt. For backwards * compatibility with existing CHAP-style API's, we perform a * layer of intermediate MD5(MD5()) hashing. This is intermediate * hashing is not required of other passwords. */ -- Avoid calling get_salt() here, because it may result in a -- migrate_passwd() call, creating a loop. SELECT INTO pw_salt salt FROM actor.passwd WHERE usr = pw_usr AND passwd_type = 'main'; -- Only migrate passwords that have not already been migrated. IF FOUND THEN RETURN pw_salt; END IF; SELECT INTO usr_row * FROM actor.usr WHERE id = pw_usr; pw_salt := actor.create_salt('main'); PERFORM actor.set_passwd( pw_usr, 'main', MD5(pw_salt || usr_row.passwd), pw_salt); -- clear the existing password UPDATE actor.usr SET passwd = '' WHERE id = usr_row.id; RETURN pw_salt; END;
Function: actor.org_unit_ancestor_at_depth(integer, integer)
Returns: org_unit
Language: SQL
SELECT a.* FROM actor.org_unit a WHERE id = ( SELECT FIRST(x.id) FROM actor.org_unit_ancestors($1) x JOIN actor.org_unit_type y ON x.ou_type = y.id AND y.depth = $2);
Function: actor.org_unit_ancestor_setting(org_id text, setting_name integer)
Returns: SET OF org_unit_setting
Language: PLPGSQL
Search "up" the org_unit tree until we find the first occurrence of an org_unit_setting with the given name.
DECLARE setting RECORD; cur_org INT; BEGIN cur_org := org_id; LOOP SELECT INTO setting * FROM actor.org_unit_setting WHERE org_unit = cur_org AND name = setting_name; IF FOUND THEN RETURN NEXT setting; EXIT; END IF; SELECT INTO cur_org parent_ou FROM actor.org_unit WHERE id = cur_org; EXIT WHEN cur_org IS NULL; END LOOP; RETURN; END;
Function: actor.org_unit_ancestor_setting_batch(setting_names integer, org_id text[])
Returns: SET OF org_unit_setting
Language: PLPGSQL
For each setting name passed, search "up" the org_unit tree until we find the first occurrence of an org_unit_setting with the given name.
DECLARE setting RECORD; setting_name TEXT; cur_org INT; BEGIN FOREACH setting_name IN ARRAY setting_names LOOP cur_org := org_id; LOOP SELECT INTO setting * FROM actor.org_unit_setting WHERE org_unit = cur_org AND name = setting_name; IF FOUND THEN RETURN NEXT setting; EXIT; END IF; SELECT INTO cur_org parent_ou FROM actor.org_unit WHERE id = cur_org; EXIT WHEN cur_org IS NULL; END LOOP; END LOOP; RETURN; END;
Function: actor.org_unit_ancestor_setting_batch_by_org(org_ids text, setting_name integer[])
Returns: SET OF org_unit_setting
Language: PLPGSQL
DECLARE setting RECORD; org_id INTEGER; BEGIN /* Returns one actor.org_unit_setting row per org unit ID provided. When no setting exists for a given org unit, the setting row will contain all empty values. */ FOREACH org_id IN ARRAY org_ids LOOP SELECT INTO setting * FROM actor.org_unit_ancestor_setting(setting_name, org_id); RETURN NEXT setting; END LOOP; RETURN; END;
Function: actor.org_unit_ancestors(integer)
Returns: SET OF org_unit
Language: SQL
WITH RECURSIVE org_unit_ancestors_distance(id, distance) AS ( SELECT $1, 0 UNION SELECT ou.parent_ou, ouad.distance+1 FROM actor.org_unit ou JOIN org_unit_ancestors_distance ouad ON (ou.id = ouad.id) WHERE ou.parent_ou IS NOT NULL ) SELECT ou.* FROM actor.org_unit ou JOIN org_unit_ancestors_distance ouad USING (id) ORDER BY ouad.distance DESC;
Function: actor.org_unit_ancestors_distance(distance integer)
Returns: SET OF record
Language: SQL
WITH RECURSIVE org_unit_ancestors_distance(id, distance) AS ( SELECT $1, 0 UNION SELECT ou.parent_ou, ouad.distance+1 FROM actor.org_unit ou JOIN org_unit_ancestors_distance ouad ON (ou.id = ouad.id) WHERE ou.parent_ou IS NOT NULL ) SELECT * FROM org_unit_ancestors_distance;
Function: actor.org_unit_combined_ancestors(integer, integer)
Returns: SET OF org_unit
Language: SQL
SELECT * FROM actor.org_unit_ancestors($1) UNION SELECT * FROM actor.org_unit_ancestors($2);
Function: actor.org_unit_common_ancestors(integer, integer)
Returns: SET OF org_unit
Language: SQL
SELECT * FROM actor.org_unit_ancestors($1) INTERSECT SELECT * FROM actor.org_unit_ancestors($2);
Function: actor.org_unit_descendants(integer)
Returns: SET OF org_unit
Language: SQL
WITH RECURSIVE descendant_depth AS ( SELECT ou.id, ou.parent_ou, out.depth FROM actor.org_unit ou JOIN actor.org_unit_type out ON (out.id = ou.ou_type) WHERE ou.id = $1 UNION ALL SELECT ou.id, ou.parent_ou, out.depth FROM actor.org_unit ou JOIN actor.org_unit_type out ON (out.id = ou.ou_type) JOIN descendant_depth ot ON (ot.id = ou.parent_ou) ) SELECT ou.* FROM actor.org_unit ou JOIN descendant_depth USING (id);
Function: actor.org_unit_descendants(integer, integer)
Returns: SET OF org_unit
Language: SQL
WITH RECURSIVE descendant_depth AS ( SELECT ou.id, ou.parent_ou, out.depth FROM actor.org_unit ou JOIN actor.org_unit_type out ON (out.id = ou.ou_type) JOIN anscestor_depth ad ON (ad.id = ou.id) WHERE ad.depth = $2 UNION ALL SELECT ou.id, ou.parent_ou, out.depth FROM actor.org_unit ou JOIN actor.org_unit_type out ON (out.id = ou.ou_type) JOIN descendant_depth ot ON (ot.id = ou.parent_ou) ), anscestor_depth AS ( SELECT ou.id, ou.parent_ou, out.depth FROM actor.org_unit ou JOIN actor.org_unit_type out ON (out.id = ou.ou_type) WHERE ou.id = $1 UNION ALL SELECT ou.id, ou.parent_ou, out.depth FROM actor.org_unit ou JOIN actor.org_unit_type out ON (out.id = ou.ou_type) JOIN anscestor_depth ot ON (ot.parent_ou = ou.id) ) SELECT ou.* FROM actor.org_unit ou JOIN descendant_depth USING (id);
Function: actor.org_unit_descendants_distance(distance integer)
Returns: SET OF record
Language: SQL
WITH RECURSIVE org_unit_descendants_distance(id, distance) AS ( SELECT $1, 0 UNION SELECT ou.id, oudd.distance+1 FROM actor.org_unit ou JOIN org_unit_descendants_distance oudd ON (ou.parent_ou = oudd.id) ) SELECT * FROM org_unit_descendants_distance;
Function: actor.org_unit_full_path(integer)
Returns: SET OF org_unit
Language: SQL
SELECT aou.* FROM actor.org_unit AS aou JOIN ( (SELECT au.id, t.depth FROM actor.org_unit_ancestors($1) AS au JOIN actor.org_unit_type t ON (au.ou_type = t.id)) UNION (SELECT au.id, t.depth FROM actor.org_unit_descendants($1) AS au JOIN actor.org_unit_type t ON (au.ou_type = t.id)) ) AS ad ON (aou.id=ad.id) ORDER BY ad.depth;
Function: actor.org_unit_full_path(integer, integer)
Returns: SET OF org_unit
Language: SQL
SELECT * FROM actor.org_unit_full_path((actor.org_unit_ancestor_at_depth($1, $2)).id)
Function: actor.org_unit_parent_protect()
Returns: trigger
Language: PLPGSQL
DECLARE current_aou actor.org_unit%ROWTYPE; seen_ous INT[]; depth_count INT; BEGIN current_aou := NEW; depth_count := 0; seen_ous := ARRAY[NEW.id]; IF (TG_OP = 'UPDATE') THEN IF (NEW.parent_ou IS NOT DISTINCT FROM OLD.parent_ou) THEN RETURN NEW; -- Doing an UPDATE with no change, just return it END IF; END IF; LOOP IF current_aou.parent_ou IS NULL THEN -- Top of the org tree? RETURN NEW; -- No loop. Carry on. END IF; IF current_aou.parent_ou = ANY(seen_ous) THEN -- Parent is one we have seen? RAISE 'OU LOOP: Saw % twice', current_aou.parent_ou; -- LOOP! ABORT! END IF; -- Get the next one! SELECT INTO current_aou * FROM actor.org_unit WHERE id = current_aou.parent_ou; seen_ous := seen_ous || current_aou.id; depth_count := depth_count + 1; IF depth_count = 100 THEN RAISE 'OU CHECK TOO DEEP'; END IF; END LOOP; RETURN NEW; END;
Function: actor.org_unit_prox_update()
Returns: trigger
Language: PLPGSQL
BEGIN IF TG_OP = 'DELETE' THEN DELETE FROM actor.org_unit_proximity WHERE (from_org = OLD.id or to_org= OLD.id); END IF; IF TG_OP = 'UPDATE' THEN IF NEW.parent_ou <> OLD.parent_ou THEN DELETE FROM actor.org_unit_proximity WHERE (from_org = OLD.id or to_org= OLD.id); INSERT INTO actor.org_unit_proximity (from_org, to_org, prox) SELECT l.id, r.id, actor.org_unit_proximity(l.id,r.id) FROM actor.org_unit l, actor.org_unit r WHERE (l.id = NEW.id or r.id = NEW.id); END IF; END IF; IF TG_OP = 'INSERT' THEN INSERT INTO actor.org_unit_proximity (from_org, to_org, prox) SELECT l.id, r.id, actor.org_unit_proximity(l.id,r.id) FROM actor.org_unit l, actor.org_unit r WHERE (l.id = NEW.id or r.id = NEW.id); END IF; RETURN null; END;
Function: actor.org_unit_proximity(integer, integer)
Returns: integer
Language: SQL
SELECT COUNT(id)::INT FROM ( SELECT id FROM actor.org_unit_combined_ancestors($1, $2) EXCEPT SELECT id FROM actor.org_unit_common_ancestors($1, $2) ) z;
Function: actor.org_unit_simple_path(integer, integer)
Returns: integer[]
Language: SQL
WITH RECURSIVE descendant_depth(id, path) AS ( SELECT aou.id, ARRAY[aou.id] FROM actor.org_unit aou JOIN actor.org_unit_type aout ON (aout.id = aou.ou_type) WHERE aou.id = $2 UNION ALL SELECT aou.id, dd.path || ARRAY[aou.id] FROM actor.org_unit aou JOIN actor.org_unit_type aout ON (aout.id = aou.ou_type) JOIN descendant_depth dd ON (dd.id = aou.parent_ou) ) SELECT dd.path FROM actor.org_unit aou JOIN descendant_depth dd USING (id) WHERE aou.id = $1 ORDER BY dd.path;
Function: actor.permit_remoteauth(userid text, profile_name bigint)
Returns: text
Language: PLPGSQL
DECLARE usr actor.usr%ROWTYPE; profile config.remoteauth_profile%ROWTYPE; perm TEXT; context_org_list INT[]; home_prox INT; block TEXT; penalty_count INT; BEGIN SELECT INTO usr * FROM actor.usr WHERE id = userid AND NOT deleted; IF usr IS NULL THEN RETURN 'not_found'; END IF; IF usr.barred IS TRUE THEN RETURN 'blocked'; END IF; SELECT INTO profile * FROM config.remoteauth_profile WHERE name = profile_name; SELECT INTO context_org_list ARRAY_AGG(id) FROM actor.org_unit_full_path( profile.context_org ); -- user's home library must be within the context org IF profile.restrict_to_org IS TRUE AND usr.home_ou NOT IN (SELECT * FROM UNNEST(context_org_list)) THEN RETURN 'not_found'; END IF; SELECT INTO perm code FROM permission.perm_list WHERE id = profile.perm; IF permission.usr_has_perm(usr.id, perm, profile.context_org) IS FALSE THEN RETURN 'not_found'; END IF; IF usr.expire_date < NOW() AND profile.allow_expired IS FALSE THEN RETURN 'expired'; END IF; IF usr.active IS FALSE AND profile.allow_inactive IS FALSE THEN RETURN 'blocked'; END IF; -- Proximity of user's home_ou to context_org to see if penalties should be ignored. SELECT INTO home_prox prox FROM actor.org_unit_proximity WHERE from_org = usr.home_ou AND to_org = profile.context_org; -- Loop through the block list to see if the user has any matching penalties. IF profile.block_list IS NOT NULL THEN FOR block IN SELECT UNNEST(STRING_TO_ARRAY(profile.block_list, '|')) LOOP SELECT INTO penalty_count COUNT(DISTINCT csp.*) FROM actor.usr_standing_penalty usp JOIN config.standing_penalty csp ON (csp.id = usp.standing_penalty) WHERE usp.usr = usr.id AND usp.org_unit IN ( SELECT * FROM UNNEST(context_org_list) ) AND ( usp.stop_date IS NULL or usp.stop_date > NOW() ) AND ( csp.ignore_proximity IS NULL OR csp.ignore_proximity < home_prox ) AND csp.block_list ~ block; IF penalty_count > 0 THEN -- User has penalties that match this block, so auth is not permitted. -- Don't bother testing the rest of the block list. RETURN 'blocked'; END IF; END LOOP; END IF; -- User has passed all tests. RETURN 'success'; END;
Function: actor.purge_usr_activity_by_type(act_type integer)
Returns: void
Language: PLPGSQL
DECLARE cur_usr INTEGER; BEGIN FOR cur_usr IN SELECT DISTINCT(usr) FROM actor.usr_activity WHERE etype = act_type LOOP DELETE FROM actor.usr_activity WHERE id IN ( SELECT id FROM actor.usr_activity WHERE usr = cur_usr AND etype = act_type ORDER BY event_time DESC OFFSET 1 ); END LOOP; END
Function: actor.restrict_usr_message_limited()
Returns: trigger
Language: PLPGSQL
BEGIN IF TG_OP = 'UPDATE' THEN UPDATE actor.usr_message SET read_date = NEW.read_date, deleted = NEW.deleted WHERE id = NEW.id; RETURN NEW; END IF; RETURN NULL; END;
Function: actor.set_passwd(new_salt integer, new_pass text, pw_type text, pw_usr text)
Returns: boolean
Language: PLPGSQL
DECLARE pw_salt TEXT; pw_text TEXT; BEGIN /* Sets the password value, creating a new actor.passwd row if needed. * If the password type supports it, the new_pass value is crypt()'ed. * For crypt'ed passwords, the salt comes from one of 3 places in order: * new_salt (if present), existing salt (if present), newly created * salt. */ IF new_salt IS NOT NULL THEN pw_salt := new_salt; ELSE pw_salt := actor.get_salt(pw_usr, pw_type); IF pw_salt IS NULL THEN /* We have no salt for this user + type. Assume they want a * new salt. If this type is unsalted, create_salt() will * return NULL. */ pw_salt := actor.create_salt(pw_type); END IF; END IF; IF pw_salt IS NULL THEN pw_text := new_pass; -- unsalted, use as-is. ELSE pw_text := CRYPT(new_pass, pw_salt); END IF; UPDATE actor.passwd SET passwd = pw_text, salt = pw_salt, edit_date = NOW() WHERE usr = pw_usr AND passwd_type = pw_type; IF NOT FOUND THEN -- no password row exists for this user + type. Create one. INSERT INTO actor.passwd (usr, passwd_type, salt, passwd) VALUES (pw_usr, pw_type, pw_salt, pw_text); END IF; RETURN TRUE; END;
Function: actor.stat_cat_check()
Returns: trigger
Language: PLPGSQL
DECLARE sipfield actor.stat_cat_sip_fields%ROWTYPE; use_count INT; BEGIN IF NEW.sip_field IS NOT NULL THEN SELECT INTO sipfield * FROM actor.stat_cat_sip_fields WHERE field = NEW.sip_field; IF sipfield.one_only THEN SELECT INTO use_count count(id) FROM actor.stat_cat WHERE sip_field = NEW.sip_field AND id != NEW.id; IF use_count > 0 THEN RAISE EXCEPTION 'Sip field cannot be used twice'; END IF; END IF; END IF; RETURN NEW; END;
Function: actor.user_ingest_name_keywords()
Returns: trigger
Language: PLPGSQL
BEGIN NEW.name_kw_tsvector := TO_TSVECTOR( COALESCE(NEW.prefix, '') || ' ' || COALESCE(NEW.first_given_name, '') || ' ' || COALESCE(evergreen.unaccent_and_squash(NEW.first_given_name), '') || ' ' || COALESCE(NEW.second_given_name, '') || ' ' || COALESCE(evergreen.unaccent_and_squash(NEW.second_given_name), '') || ' ' || COALESCE(NEW.family_name, '') || ' ' || COALESCE(evergreen.unaccent_and_squash(NEW.family_name), '') || ' ' || COALESCE(NEW.suffix, '') || ' ' || COALESCE(NEW.pref_prefix, '') || ' ' || COALESCE(NEW.pref_first_given_name, '') || ' ' || COALESCE(evergreen.unaccent_and_squash(NEW.pref_first_given_name), '') || ' ' || COALESCE(NEW.pref_second_given_name, '') || ' ' || COALESCE(evergreen.unaccent_and_squash(NEW.pref_second_given_name), '') || ' ' || COALESCE(NEW.pref_family_name, '') || ' ' || COALESCE(evergreen.unaccent_and_squash(NEW.pref_family_name), '') || ' ' || COALESCE(NEW.pref_suffix, '') || ' ' || COALESCE(NEW.name_keywords, '') ); RETURN NEW; END;
Function: actor.usr_activity_get_type(ehow text, ewhat text, ewho text)
Returns: SET OF usr_activity_type
Language: SQL
SELECT * FROM config.usr_activity_type WHERE enabled AND (ewho IS NULL OR ewho = $1) AND (ewhat IS NULL OR ewhat = $2) AND (ehow IS NULL OR ehow = $3) ORDER BY -- BOOL comparisons sort false to true COALESCE(ewho, '') != COALESCE($1, ''), COALESCE(ewhat,'') != COALESCE($2, ''), COALESCE(ehow, '') != COALESCE($3, '') LIMIT 1;
Function: actor.usr_activity_transient_trg()
Returns: trigger
Language: PLPGSQL
BEGIN DELETE FROM actor.usr_activity act USING config.usr_activity_type atype WHERE atype.transient AND NEW.etype = atype.id AND act.etype = atype.id AND act.usr = NEW.usr; RETURN NEW; END;
Function: actor.usr_delete(dest_usr integer, src_usr integer)
Returns: void
Language: PLPGSQL
Logically deletes a user. Removes personally identifiable information, and purges associated data in other tables.
DECLARE old_profile actor.usr.profile%type; old_home_ou actor.usr.home_ou%type; new_profile actor.usr.profile%type; new_home_ou actor.usr.home_ou%type; new_name text; new_dob actor.usr.dob%type; BEGIN SELECT id || '-PURGED-' || now(), profile, home_ou, dob INTO new_name, old_profile, old_home_ou, new_dob FROM actor.usr WHERE id = src_usr; -- -- Quit if no such user -- IF old_profile IS NULL THEN RETURN; END IF; -- perform actor.usr_purge_data( src_usr, dest_usr ); -- -- Find the root grp_tree and the root org_unit. This would be simpler if we -- could assume that there is only one root. Theoretically, someday, maybe, -- there could be multiple roots, so we take extra trouble to get the right ones. -- SELECT id INTO new_profile FROM permission.grp_ancestors( old_profile ) WHERE parent is null; -- SELECT id INTO new_home_ou FROM actor.org_unit_ancestors( old_home_ou ) WHERE parent_ou is null; -- -- Truncate date of birth -- IF new_dob IS NOT NULL THEN new_dob := date_trunc( 'year', new_dob ); END IF; -- UPDATE actor.usr SET card = NULL, profile = new_profile, usrname = new_name, email = NULL, passwd = random()::text, standing = DEFAULT, ident_type = ( SELECT MIN( id ) FROM config.identification_type ), ident_value = NULL, ident_type2 = NULL, ident_value2 = NULL, net_access_level = DEFAULT, photo_url = NULL, prefix = NULL, first_given_name = new_name, second_given_name = NULL, family_name = new_name, suffix = NULL, alias = NULL, guardian = NULL, day_phone = NULL, evening_phone = NULL, other_phone = NULL, mailing_address = NULL, billing_address = NULL, home_ou = new_home_ou, dob = new_dob, active = FALSE, master_account = DEFAULT, super_user = DEFAULT, barred = FALSE, deleted = TRUE, juvenile = DEFAULT, usrgroup = 0, claims_returned_count = DEFAULT, credit_forward_balance = DEFAULT, last_xact_id = DEFAULT, pref_prefix = NULL, pref_first_given_name = NULL, pref_second_given_name = NULL, pref_family_name = NULL, pref_suffix = NULL, name_keywords = NULL, create_date = now(), expire_date = now() WHERE id = src_usr; END;
Function: actor.usr_merge(deactivate_cards integer, del_cards integer, del_addrs boolean, dest_usr boolean, src_usr boolean)
Returns: void
Language: PLPGSQL
Merges all user date from src_usr to dest_usr. When collisions occur, keep dest_usr's data and delete src_usr's data.
DECLARE suffix TEXT; bucket_row RECORD; picklist_row RECORD; queue_row RECORD; folder_row RECORD; BEGIN -- Bail if src_usr equals dest_usr because the result of merging a -- user with itself is not what you want. IF src_usr = dest_usr THEN RETURN; END IF; -- do some initial cleanup UPDATE actor.usr SET card = NULL WHERE id = src_usr; UPDATE actor.usr SET mailing_address = NULL WHERE id = src_usr; UPDATE actor.usr SET billing_address = NULL WHERE id = src_usr; -- actor.* IF del_cards THEN DELETE FROM actor.card where usr = src_usr; ELSE IF deactivate_cards THEN UPDATE actor.card SET active = 'f' WHERE usr = src_usr; END IF; UPDATE actor.card SET usr = dest_usr WHERE usr = src_usr; END IF; IF del_addrs THEN DELETE FROM actor.usr_address WHERE usr = src_usr; ELSE UPDATE actor.usr_address SET usr = dest_usr WHERE usr = src_usr; END IF; UPDATE actor.usr_message SET usr = dest_usr WHERE usr = src_usr; -- dupes are technically OK in actor.usr_standing_penalty, should manually delete them... UPDATE actor.usr_standing_penalty SET usr = dest_usr WHERE usr = src_usr; PERFORM actor.usr_merge_rows('actor.usr_org_unit_opt_in', 'usr', src_usr, dest_usr); PERFORM actor.usr_merge_rows('actor.usr_setting', 'usr', src_usr, dest_usr); -- permission.* PERFORM actor.usr_merge_rows('permission.usr_perm_map', 'usr', src_usr, dest_usr); PERFORM actor.usr_merge_rows('permission.usr_object_perm_map', 'usr', src_usr, dest_usr); PERFORM actor.usr_merge_rows('permission.usr_grp_map', 'usr', src_usr, dest_usr); PERFORM actor.usr_merge_rows('permission.usr_work_ou_map', 'usr', src_usr, dest_usr); -- container.* -- For each *_bucket table: transfer every bucket belonging to src_usr -- into the custody of dest_usr. -- -- In order to avoid colliding with an existing bucket owned by -- the destination user, append the source user's id (in parenthesese) -- to the name. If you still get a collision, add successive -- spaces to the name and keep trying until you succeed. -- FOR bucket_row in SELECT id, name FROM container.biblio_record_entry_bucket WHERE owner = src_usr LOOP suffix := ' (' || src_usr || ')'; LOOP BEGIN UPDATE container.biblio_record_entry_bucket SET owner = dest_usr, name = name || suffix WHERE id = bucket_row.id; EXCEPTION WHEN unique_violation THEN suffix := suffix || ' '; CONTINUE; END; EXIT; END LOOP; END LOOP; FOR bucket_row in SELECT id, name FROM container.call_number_bucket WHERE owner = src_usr LOOP suffix := ' (' || src_usr || ')'; LOOP BEGIN UPDATE container.call_number_bucket SET owner = dest_usr, name = name || suffix WHERE id = bucket_row.id; EXCEPTION WHEN unique_violation THEN suffix := suffix || ' '; CONTINUE; END; EXIT; END LOOP; END LOOP; FOR bucket_row in SELECT id, name FROM container.copy_bucket WHERE owner = src_usr LOOP suffix := ' (' || src_usr || ')'; LOOP BEGIN UPDATE container.copy_bucket SET owner = dest_usr, name = name || suffix WHERE id = bucket_row.id; EXCEPTION WHEN unique_violation THEN suffix := suffix || ' '; CONTINUE; END; EXIT; END LOOP; END LOOP; FOR bucket_row in SELECT id, name FROM container.user_bucket WHERE owner = src_usr LOOP suffix := ' (' || src_usr || ')'; LOOP BEGIN UPDATE container.user_bucket SET owner = dest_usr, name = name || suffix WHERE id = bucket_row.id; EXCEPTION WHEN unique_violation THEN suffix := suffix || ' '; CONTINUE; END; EXIT; END LOOP; END LOOP; UPDATE container.user_bucket_item SET target_user = dest_usr WHERE target_user = src_usr; -- vandelay.* -- transfer queues the same way we transfer buckets (see above) FOR queue_row in SELECT id, name FROM vandelay.queue WHERE owner = src_usr LOOP suffix := ' (' || src_usr || ')'; LOOP BEGIN UPDATE vandelay.queue SET owner = dest_usr, name = name || suffix WHERE id = queue_row.id; EXCEPTION WHEN unique_violation THEN suffix := suffix || ' '; CONTINUE; END; EXIT; END LOOP; END LOOP; UPDATE vandelay.session_tracker SET usr = dest_usr WHERE usr = src_usr; -- money.* PERFORM actor.usr_merge_rows('money.collections_tracker', 'usr', src_usr, dest_usr); PERFORM actor.usr_merge_rows('money.collections_tracker', 'collector', src_usr, dest_usr); UPDATE money.billable_xact SET usr = dest_usr WHERE usr = src_usr; UPDATE money.billing SET voider = dest_usr WHERE voider = src_usr; UPDATE money.bnm_payment SET accepting_usr = dest_usr WHERE accepting_usr = src_usr; -- action.* UPDATE action.circulation SET usr = dest_usr WHERE usr = src_usr; UPDATE action.circulation SET circ_staff = dest_usr WHERE circ_staff = src_usr; UPDATE action.circulation SET checkin_staff = dest_usr WHERE checkin_staff = src_usr; UPDATE action.usr_circ_history SET usr = dest_usr WHERE usr = src_usr; UPDATE action.hold_request SET usr = dest_usr WHERE usr = src_usr; UPDATE action.hold_request SET fulfillment_staff = dest_usr WHERE fulfillment_staff = src_usr; UPDATE action.hold_request SET requestor = dest_usr WHERE requestor = src_usr; UPDATE action.hold_notification SET notify_staff = dest_usr WHERE notify_staff = src_usr; UPDATE action.in_house_use SET staff = dest_usr WHERE staff = src_usr; UPDATE action.non_cataloged_circulation SET staff = dest_usr WHERE staff = src_usr; UPDATE action.non_cataloged_circulation SET patron = dest_usr WHERE patron = src_usr; UPDATE action.non_cat_in_house_use SET staff = dest_usr WHERE staff = src_usr; UPDATE action.survey_response SET usr = dest_usr WHERE usr = src_usr; -- acq.* UPDATE acq.fund_allocation SET allocator = dest_usr WHERE allocator = src_usr; UPDATE acq.fund_transfer SET transfer_user = dest_usr WHERE transfer_user = src_usr; UPDATE acq.invoice SET closed_by = dest_usr WHERE closed_by = src_usr; -- transfer picklists the same way we transfer buckets (see above) FOR picklist_row in SELECT id, name FROM acq.picklist WHERE owner = src_usr LOOP suffix := ' (' || src_usr || ')'; LOOP BEGIN UPDATE acq.picklist SET owner = dest_usr, name = name || suffix WHERE id = picklist_row.id; EXCEPTION WHEN unique_violation THEN suffix := suffix || ' '; CONTINUE; END; EXIT; END LOOP; END LOOP; UPDATE acq.purchase_order SET owner = dest_usr WHERE owner = src_usr; UPDATE acq.po_note SET creator = dest_usr WHERE creator = src_usr; UPDATE acq.po_note SET editor = dest_usr WHERE editor = src_usr; UPDATE acq.provider_note SET creator = dest_usr WHERE creator = src_usr; UPDATE acq.provider_note SET editor = dest_usr WHERE editor = src_usr; UPDATE acq.lineitem_note SET creator = dest_usr WHERE creator = src_usr; UPDATE acq.lineitem_note SET editor = dest_usr WHERE editor = src_usr; UPDATE acq.lineitem_usr_attr_definition SET usr = dest_usr WHERE usr = src_usr; -- asset.* UPDATE asset.copy SET creator = dest_usr WHERE creator = src_usr; UPDATE asset.copy SET editor = dest_usr WHERE editor = src_usr; UPDATE asset.copy_note SET creator = dest_usr WHERE creator = src_usr; UPDATE asset.call_number SET creator = dest_usr WHERE creator = src_usr; UPDATE asset.call_number SET editor = dest_usr WHERE editor = src_usr; UPDATE asset.call_number_note SET creator = dest_usr WHERE creator = src_usr; -- serial.* UPDATE serial.record_entry SET creator = dest_usr WHERE creator = src_usr; UPDATE serial.record_entry SET editor = dest_usr WHERE editor = src_usr; -- reporter.* -- It's not uncommon to define the reporter schema in a replica -- DB only, so don't assume these tables exist in the write DB. BEGIN UPDATE reporter.template SET owner = dest_usr WHERE owner = src_usr; EXCEPTION WHEN undefined_table THEN -- do nothing END; BEGIN UPDATE reporter.report SET owner = dest_usr WHERE owner = src_usr; EXCEPTION WHEN undefined_table THEN -- do nothing END; BEGIN UPDATE reporter.schedule SET runner = dest_usr WHERE runner = src_usr; EXCEPTION WHEN undefined_table THEN -- do nothing END; BEGIN -- transfer folders the same way we transfer buckets (see above) FOR folder_row in SELECT id, name FROM reporter.template_folder WHERE owner = src_usr LOOP suffix := ' (' || src_usr || ')'; LOOP BEGIN UPDATE reporter.template_folder SET owner = dest_usr, name = name || suffix WHERE id = folder_row.id; EXCEPTION WHEN unique_violation THEN suffix := suffix || ' '; CONTINUE; END; EXIT; END LOOP; END LOOP; EXCEPTION WHEN undefined_table THEN -- do nothing END; BEGIN -- transfer folders the same way we transfer buckets (see above) FOR folder_row in SELECT id, name FROM reporter.report_folder WHERE owner = src_usr LOOP suffix := ' (' || src_usr || ')'; LOOP BEGIN UPDATE reporter.report_folder SET owner = dest_usr, name = name || suffix WHERE id = folder_row.id; EXCEPTION WHEN unique_violation THEN suffix := suffix || ' '; CONTINUE; END; EXIT; END LOOP; END LOOP; EXCEPTION WHEN undefined_table THEN -- do nothing END; BEGIN -- transfer folders the same way we transfer buckets (see above) FOR folder_row in SELECT id, name FROM reporter.output_folder WHERE owner = src_usr LOOP suffix := ' (' || src_usr || ')'; LOOP BEGIN UPDATE reporter.output_folder SET owner = dest_usr, name = name || suffix WHERE id = folder_row.id; EXCEPTION WHEN unique_violation THEN suffix := suffix || ' '; CONTINUE; END; EXIT; END LOOP; END LOOP; EXCEPTION WHEN undefined_table THEN -- do nothing END; -- propagate preferred name values from the source user to the -- destination user, but only when values are not being replaced. WITH susr AS (SELECT * FROM actor.usr WHERE id = src_usr) UPDATE actor.usr SET pref_prefix = COALESCE(pref_prefix, (SELECT pref_prefix FROM susr)), pref_first_given_name = COALESCE(pref_first_given_name, (SELECT pref_first_given_name FROM susr)), pref_second_given_name = COALESCE(pref_second_given_name, (SELECT pref_second_given_name FROM susr)), pref_family_name = COALESCE(pref_family_name, (SELECT pref_family_name FROM susr)), pref_suffix = COALESCE(pref_suffix, (SELECT pref_suffix FROM susr)) WHERE id = dest_usr; -- Copy and deduplicate name keywords -- String -> array -> rows -> DISTINCT -> array -> string WITH susr AS (SELECT * FROM actor.usr WHERE id = src_usr), dusr AS (SELECT * FROM actor.usr WHERE id = dest_usr) UPDATE actor.usr SET name_keywords = ( WITH keywords AS ( SELECT DISTINCT UNNEST( REGEXP_SPLIT_TO_ARRAY( COALESCE((SELECT name_keywords FROM susr), '') || ' ' || COALESCE((SELECT name_keywords FROM dusr), ''), E'\\s+' ) ) AS parts ) SELECT STRING_AGG(kw.parts, ' ') FROM keywords kw ) WHERE id = dest_usr; -- Finally, delete the source user PERFORM actor.usr_delete(src_usr,dest_usr); END;
Function: actor.usr_merge_rows(dest_usr text, src_usr text, col_name integer, table_name integer)
Returns: void
Language: PLPGSQL
Attempts to move each row of the specified table from src_user to dest_user. Where conflicts exist, the conflicting "source" row is deleted.
DECLARE sel TEXT; upd TEXT; del TEXT; cur_row RECORD; BEGIN sel := 'SELECT id::BIGINT FROM ' || table_name || ' WHERE ' || quote_ident(col_name) || ' = ' || quote_literal(src_usr); upd := 'UPDATE ' || table_name || ' SET ' || quote_ident(col_name) || ' = ' || quote_literal(dest_usr) || ' WHERE id = '; del := 'DELETE FROM ' || table_name || ' WHERE id = '; FOR cur_row IN EXECUTE sel LOOP BEGIN --RAISE NOTICE 'Attempting to merge % %', table_name, cur_row.id; EXECUTE upd || cur_row.id; EXCEPTION WHEN unique_violation THEN --RAISE NOTICE 'Deleting conflicting % %', table_name, cur_row.id; EXECUTE del || cur_row.id; END; END LOOP; END;
Function: actor.usr_purge_data(specified_dest_usr integer, src_usr integer)
Returns: void
Language: PLPGSQL
Finds rows dependent on a given row in actor.usr and either deletes them or reassigns them to a different user.
DECLARE suffix TEXT; renamable_row RECORD; dest_usr INTEGER; BEGIN IF specified_dest_usr IS NULL THEN dest_usr := 1; -- Admin user on stock installs ELSE dest_usr := specified_dest_usr; END IF; -- action_trigger.event (even doing this, event_output may--and probably does--contain PII and should have a retention/removal policy) UPDATE action_trigger.event SET context_user = dest_usr WHERE context_user = src_usr; -- acq.* UPDATE acq.fund_allocation SET allocator = dest_usr WHERE allocator = src_usr; UPDATE acq.lineitem SET creator = dest_usr WHERE creator = src_usr; UPDATE acq.lineitem SET editor = dest_usr WHERE editor = src_usr; UPDATE acq.lineitem SET selector = dest_usr WHERE selector = src_usr; UPDATE acq.lineitem_note SET creator = dest_usr WHERE creator = src_usr; UPDATE acq.lineitem_note SET editor = dest_usr WHERE editor = src_usr; UPDATE acq.invoice SET closed_by = dest_usr WHERE closed_by = src_usr; DELETE FROM acq.lineitem_usr_attr_definition WHERE usr = src_usr; -- Update with a rename to avoid collisions FOR renamable_row in SELECT id, name FROM acq.picklist WHERE owner = src_usr LOOP suffix := ' (' || src_usr || ')'; LOOP BEGIN UPDATE acq.picklist SET owner = dest_usr, name = name || suffix WHERE id = renamable_row.id; EXCEPTION WHEN unique_violation THEN suffix := suffix || ' '; CONTINUE; END; EXIT; END LOOP; END LOOP; UPDATE acq.picklist SET creator = dest_usr WHERE creator = src_usr; UPDATE acq.picklist SET editor = dest_usr WHERE editor = src_usr; UPDATE acq.po_note SET creator = dest_usr WHERE creator = src_usr; UPDATE acq.po_note SET editor = dest_usr WHERE editor = src_usr; UPDATE acq.purchase_order SET owner = dest_usr WHERE owner = src_usr; UPDATE acq.purchase_order SET creator = dest_usr WHERE creator = src_usr; UPDATE acq.purchase_order SET editor = dest_usr WHERE editor = src_usr; UPDATE acq.claim_event SET creator = dest_usr WHERE creator = src_usr; -- action.* DELETE FROM action.circulation WHERE usr = src_usr; UPDATE action.circulation SET circ_staff = dest_usr WHERE circ_staff = src_usr; UPDATE action.circulation SET checkin_staff = dest_usr WHERE checkin_staff = src_usr; UPDATE action.hold_notification SET notify_staff = dest_usr WHERE notify_staff = src_usr; UPDATE action.hold_request SET fulfillment_staff = dest_usr WHERE fulfillment_staff = src_usr; UPDATE action.hold_request SET requestor = dest_usr WHERE requestor = src_usr; DELETE FROM action.hold_request WHERE usr = src_usr; UPDATE action.in_house_use SET staff = dest_usr WHERE staff = src_usr; UPDATE action.non_cat_in_house_use SET staff = dest_usr WHERE staff = src_usr; DELETE FROM action.non_cataloged_circulation WHERE patron = src_usr; UPDATE action.non_cataloged_circulation SET staff = dest_usr WHERE staff = src_usr; DELETE FROM action.survey_response WHERE usr = src_usr; UPDATE action.fieldset SET owner = dest_usr WHERE owner = src_usr; DELETE FROM action.usr_circ_history WHERE usr = src_usr; UPDATE action.curbside SET notes = NULL WHERE patron = src_usr; -- actor.* DELETE FROM actor.card WHERE usr = src_usr; DELETE FROM actor.stat_cat_entry_usr_map WHERE target_usr = src_usr; DELETE FROM actor.usr_privacy_waiver WHERE usr = src_usr; DELETE FROM actor.usr_message WHERE usr = src_usr; -- The following update is intended to avoid transient violations of a foreign -- key constraint, whereby actor.usr_address references itself. It may not be -- necessary, but it does no harm. UPDATE actor.usr_address SET replaces = NULL WHERE usr = src_usr AND replaces IS NOT NULL; DELETE FROM actor.usr_address WHERE usr = src_usr; DELETE FROM actor.usr_org_unit_opt_in WHERE usr = src_usr; UPDATE actor.usr_org_unit_opt_in SET staff = dest_usr WHERE staff = src_usr; DELETE FROM actor.usr_setting WHERE usr = src_usr; DELETE FROM actor.usr_standing_penalty WHERE usr = src_usr; UPDATE actor.usr_message SET title = 'purged', message = 'purged', read_date = NOW() WHERE usr = src_usr; DELETE FROM actor.usr_message WHERE usr = src_usr; UPDATE actor.usr_standing_penalty SET staff = dest_usr WHERE staff = src_usr; UPDATE actor.usr_message SET editor = dest_usr WHERE editor = src_usr; -- asset.* UPDATE asset.call_number SET creator = dest_usr WHERE creator = src_usr; UPDATE asset.call_number SET editor = dest_usr WHERE editor = src_usr; UPDATE asset.call_number_note SET creator = dest_usr WHERE creator = src_usr; UPDATE asset.copy SET creator = dest_usr WHERE creator = src_usr; UPDATE asset.copy SET editor = dest_usr WHERE editor = src_usr; UPDATE asset.copy_note SET creator = dest_usr WHERE creator = src_usr; -- auditor.* DELETE FROM auditor.actor_usr_address_history WHERE id = src_usr; DELETE FROM auditor.actor_usr_history WHERE id = src_usr; UPDATE auditor.asset_call_number_history SET creator = dest_usr WHERE creator = src_usr; UPDATE auditor.asset_call_number_history SET editor = dest_usr WHERE editor = src_usr; UPDATE auditor.asset_copy_history SET creator = dest_usr WHERE creator = src_usr; UPDATE auditor.asset_copy_history SET editor = dest_usr WHERE editor = src_usr; UPDATE auditor.biblio_record_entry_history SET creator = dest_usr WHERE creator = src_usr; UPDATE auditor.biblio_record_entry_history SET editor = dest_usr WHERE editor = src_usr; -- biblio.* UPDATE biblio.record_entry SET creator = dest_usr WHERE creator = src_usr; UPDATE biblio.record_entry SET editor = dest_usr WHERE editor = src_usr; UPDATE biblio.record_note SET creator = dest_usr WHERE creator = src_usr; UPDATE biblio.record_note SET editor = dest_usr WHERE editor = src_usr; -- container.* -- Update buckets with a rename to avoid collisions FOR renamable_row in SELECT id, name FROM container.biblio_record_entry_bucket WHERE owner = src_usr LOOP suffix := ' (' || src_usr || ')'; LOOP BEGIN UPDATE container.biblio_record_entry_bucket SET owner = dest_usr, name = name || suffix WHERE id = renamable_row.id; EXCEPTION WHEN unique_violation THEN suffix := suffix || ' '; CONTINUE; END; EXIT; END LOOP; END LOOP; FOR renamable_row in SELECT id, name FROM container.call_number_bucket WHERE owner = src_usr LOOP suffix := ' (' || src_usr || ')'; LOOP BEGIN UPDATE container.call_number_bucket SET owner = dest_usr, name = name || suffix WHERE id = renamable_row.id; EXCEPTION WHEN unique_violation THEN suffix := suffix || ' '; CONTINUE; END; EXIT; END LOOP; END LOOP; FOR renamable_row in SELECT id, name FROM container.copy_bucket WHERE owner = src_usr LOOP suffix := ' (' || src_usr || ')'; LOOP BEGIN UPDATE container.copy_bucket SET owner = dest_usr, name = name || suffix WHERE id = renamable_row.id; EXCEPTION WHEN unique_violation THEN suffix := suffix || ' '; CONTINUE; END; EXIT; END LOOP; END LOOP; FOR renamable_row in SELECT id, name FROM container.user_bucket WHERE owner = src_usr LOOP suffix := ' (' || src_usr || ')'; LOOP BEGIN UPDATE container.user_bucket SET owner = dest_usr, name = name || suffix WHERE id = renamable_row.id; EXCEPTION WHEN unique_violation THEN suffix := suffix || ' '; CONTINUE; END; EXIT; END LOOP; END LOOP; DELETE FROM container.user_bucket_item WHERE target_user = src_usr; -- money.* DELETE FROM money.billable_xact WHERE usr = src_usr; DELETE FROM money.collections_tracker WHERE usr = src_usr; UPDATE money.collections_tracker SET collector = dest_usr WHERE collector = src_usr; -- permission.* DELETE FROM permission.usr_grp_map WHERE usr = src_usr; DELETE FROM permission.usr_object_perm_map WHERE usr = src_usr; DELETE FROM permission.usr_perm_map WHERE usr = src_usr; DELETE FROM permission.usr_work_ou_map WHERE usr = src_usr; -- reporter.* -- Update with a rename to avoid collisions BEGIN FOR renamable_row in SELECT id, name FROM reporter.output_folder WHERE owner = src_usr LOOP suffix := ' (' || src_usr || ')'; LOOP BEGIN UPDATE reporter.output_folder SET owner = dest_usr, name = name || suffix WHERE id = renamable_row.id; EXCEPTION WHEN unique_violation THEN suffix := suffix || ' '; CONTINUE; END; EXIT; END LOOP; END LOOP; EXCEPTION WHEN undefined_table THEN -- do nothing END; BEGIN UPDATE reporter.report SET owner = dest_usr WHERE owner = src_usr; EXCEPTION WHEN undefined_table THEN -- do nothing END; -- Update with a rename to avoid collisions BEGIN FOR renamable_row in SELECT id, name FROM reporter.report_folder WHERE owner = src_usr LOOP suffix := ' (' || src_usr || ')'; LOOP BEGIN UPDATE reporter.report_folder SET owner = dest_usr, name = name || suffix WHERE id = renamable_row.id; EXCEPTION WHEN unique_violation THEN suffix := suffix || ' '; CONTINUE; END; EXIT; END LOOP; END LOOP; EXCEPTION WHEN undefined_table THEN -- do nothing END; BEGIN UPDATE reporter.schedule SET runner = dest_usr WHERE runner = src_usr; EXCEPTION WHEN undefined_table THEN -- do nothing END; BEGIN UPDATE reporter.template SET owner = dest_usr WHERE owner = src_usr; EXCEPTION WHEN undefined_table THEN -- do nothing END; -- Update with a rename to avoid collisions BEGIN FOR renamable_row in SELECT id, name FROM reporter.template_folder WHERE owner = src_usr LOOP suffix := ' (' || src_usr || ')'; LOOP BEGIN UPDATE reporter.template_folder SET owner = dest_usr, name = name || suffix WHERE id = renamable_row.id; EXCEPTION WHEN unique_violation THEN suffix := suffix || ' '; CONTINUE; END; EXIT; END LOOP; END LOOP; EXCEPTION WHEN undefined_table THEN -- do nothing END; -- vandelay.* -- Update with a rename to avoid collisions FOR renamable_row in SELECT id, name FROM vandelay.queue WHERE owner = src_usr LOOP suffix := ' (' || src_usr || ')'; LOOP BEGIN UPDATE vandelay.queue SET owner = dest_usr, name = name || suffix WHERE id = renamable_row.id; EXCEPTION WHEN unique_violation THEN suffix := suffix || ' '; CONTINUE; END; EXIT; END LOOP; END LOOP; UPDATE vandelay.session_tracker SET usr = dest_usr WHERE usr = src_usr; -- NULL-ify addresses last so other cleanup (e.g. circ anonymization) -- can access the information before deletion. UPDATE actor.usr SET active = FALSE, card = NULL, mailing_address = NULL, billing_address = NULL WHERE id = src_usr; END;
Function: actor.verify_passwd(test_passwd integer, pw_type text, pw_usr text)
Returns: boolean
Language: PLPGSQL
DECLARE pw_salt TEXT; BEGIN /* Returns TRUE if the password provided matches the in-db password. * If the password type is salted, we compare the output of CRYPT(). * NOTE: test_passwd is MD5(salt || MD5(password)) for legacy * 'main' passwords. */ SELECT INTO pw_salt salt FROM actor.passwd WHERE usr = pw_usr AND passwd_type = pw_type; IF NOT FOUND THEN -- no such password RETURN FALSE; END IF; IF pw_salt IS NULL THEN -- Password is unsalted, compare the un-CRYPT'ed values. RETURN EXISTS ( SELECT TRUE FROM actor.passwd WHERE usr = pw_usr AND passwd_type = pw_type AND passwd = test_passwd ); END IF; RETURN EXISTS ( SELECT TRUE FROM actor.passwd WHERE usr = pw_usr AND passwd_type = pw_type AND passwd = CRYPT(test_passwd, pw_salt) ); END;
Schema asset
View: asset.active_copy_alert
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
alert_type | integer | ||
copy | bigint | ||
temp | boolean | ||
create_time | timestamp with time zone | ||
create_staff | bigint | ||
note | text | ||
ack_time | timestamp with time zone | ||
ack_staff | bigint |
SELECT copy_alert.id , copy_alert.alert_type , copy_alert.copy , copy_alert.temp , copy_alert.create_time , copy_alert.create_staff , copy_alert.note , copy_alert.ack_time , copy_alert.ack_staff FROM asset.copy_alert WHERE (copy_alert.ack_time IS NULL);
Table: asset.call_number
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
actor.usr.id | creator | bigint | NOT NULL |
create_date | timestamp with time zone | DEFAULT now() | |
actor.usr.id | editor | bigint | NOT NULL |
edit_date | timestamp with time zone | DEFAULT now() | |
biblio.record_entry.id | record | bigint | NOT NULL |
actor.org_unit.id | owning_lib | integer | NOT NULL |
label | text | NOT NULL | |
deleted | boolean | NOT NULL DEFAULT false | |
asset.call_number_prefix.id | prefix | integer | NOT NULL DEFAULT '-1'::integer |
asset.call_number_suffix.id | suffix | integer | NOT NULL DEFAULT '-1'::integer |
asset.call_number_class.id | label_class | bigint | NOT NULL |
label_sortkey | text |
Tables referencing this one via Foreign Key Constraints:
asset_call_number_creator_idx creator asset_call_number_dewey_idx call_number_dewey(label) asset_call_number_editor_idx editor asset_call_number_label_sortkey oils_text_as_bytea(label_sortkey) asset_call_number_label_sortkey_browse oils_text_as_bytea(label_sortkey), oils_text_as_bytea(label), id, owning_lib) WHERE ((deleted IS FALSE) OR (deleted = false) asset_call_number_record_idx record asset_call_number_upper_label_id_owning_lib_idx oils_text_as_bytea(label), id, owning_libTable: asset.call_number_class
Defines the call number normalization database functions in the "normalizer" column and the tag/subfield combinations to use to lookup the call number in the "field" column for a given classification scheme. Tag/subfield combinations are delimited by commas.
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
name | text | NOT NULL | |
normalizer | text | NOT NULL DEFAULT 'asset.normalize_generic'::text | |
field | text | NOT NULL DEFAULT '050ab,055ab,060ab,070ab,080ab,082ab,086ab,088ab,090,092,096,098,099'::text |
Tables referencing this one via Foreign Key Constraints:
Table: asset.call_number_note
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
asset.call_number.id | call_number | bigint | NOT NULL |
actor.usr.id | creator | bigint | NOT NULL |
create_date | timestamp with time zone | DEFAULT now() | |
pub | boolean | NOT NULL DEFAULT false | |
title | text | NOT NULL | |
value | text | NOT NULL |
Table: asset.call_number_prefix
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | owning_lib | integer | NOT NULL |
label | text | NOT NULL | |
label_sortkey | text |
Tables referencing this one via Foreign Key Constraints:
asset_call_number_prefix_sortkey_idx label_sortkeyTable: asset.call_number_suffix
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | owning_lib | integer | NOT NULL |
label | text | NOT NULL | |
label_sortkey | text |
Tables referencing this one via Foreign Key Constraints:
asset_call_number_suffix_sortkey_idx label_sortkeyTable: asset.copy
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
actor.org_unit.id | circ_lib | integer | NOT NULL |
actor.usr.id | creator | bigint | NOT NULL |
asset.call_number.id | call_number | bigint | NOT NULL |
actor.usr.id | editor | bigint | NOT NULL |
create_date | timestamp with time zone | DEFAULT now() | |
edit_date | timestamp with time zone | DEFAULT now() | |
copy_number | integer | ||
config.copy_status.id | status | integer | NOT NULL |
asset.copy_location.id | location | integer | NOT NULL DEFAULT 1 |
loan_duration | integer | NOT NULL | |
fine_level | integer | NOT NULL | |
age_protect | integer | ||
circulate | boolean | NOT NULL DEFAULT true | |
deposit | boolean | NOT NULL DEFAULT false | |
ref | boolean | NOT NULL DEFAULT false | |
holdable | boolean | NOT NULL DEFAULT true | |
deposit_amount | numeric(6,2) | NOT NULL DEFAULT 0.00 | |
price | numeric(8,2) | ||
barcode | text | NOT NULL | |
config.circ_modifier.code | circ_modifier | text | |
circ_as_type | text | ||
dummy_title | text | ||
dummy_author | text | ||
alert_message | text | ||
opac_visible | boolean | NOT NULL DEFAULT true | |
deleted | boolean | NOT NULL DEFAULT false | |
config.floating_group.id | floating | integer | |
dummy_isbn | text | ||
status_changed_time | timestamp with time zone | ||
active_date | timestamp with time zone | ||
mint_condition | boolean | NOT NULL DEFAULT true | |
cost | numeric(8,2) |
Name | Constraint |
---|---|
copy_fine_level_check | CHECK ((fine_level = ANY (ARRAY[1, 2, 3]))) |
copy_loan_duration_check | CHECK ((loan_duration = ANY (ARRAY[1, 2, 3]))) |
Tables referencing this one via Foreign Key Constraints:
cp_avail_cn_idx call_number cp_available_by_circ_lib_idx circ_lib) WHERE (status = ANY (ARRAY[0, 7]) cp_cn_idx call_number cp_create_date create_date cp_creator_idx creator cp_editor_idx editorTable: asset.copy_alert
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
config.copy_alert_type.id | alert_type | integer | NOT NULL |
copy | bigint | NOT NULL | |
temp | boolean | NOT NULL DEFAULT false | |
create_time | timestamp with time zone | NOT NULL DEFAULT now() | |
actor.usr.id | create_staff | bigint | NOT NULL |
note | text | ||
ack_time | timestamp with time zone | ||
actor.usr.id | ack_staff | bigint |
Table: asset.copy_inventory
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.workstation.id | inventory_workstation | integer | |
inventory_date | timestamp with time zone | NOT NULL DEFAULT now() | |
copy | bigint | NOT NULL |
Table: asset.copy_location
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | NOT NULL | |
actor.org_unit.id | owning_lib | integer | NOT NULL |
holdable | boolean | NOT NULL DEFAULT true | |
hold_verify | boolean | NOT NULL DEFAULT false | |
opac_visible | boolean | NOT NULL DEFAULT true | |
circulate | boolean | NOT NULL DEFAULT true | |
label_prefix | text | ||
label_suffix | text | ||
checkin_alert | boolean | NOT NULL DEFAULT false | |
deleted | boolean | NOT NULL DEFAULT false | |
url | text |
Tables referencing this one via Foreign Key Constraints:
Table: asset.copy_location_group
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE#1 NOT NULL | |
actor.org_unit.id | owner | integer | UNIQUE#1 NOT NULL |
pos | integer | NOT NULL | |
top | boolean | NOT NULL DEFAULT false | |
opac_visible | boolean | NOT NULL DEFAULT true |
Tables referencing this one via Foreign Key Constraints:
Table: asset.copy_location_group_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
asset.copy_location.id | location | integer | UNIQUE#1 NOT NULL |
asset.copy_location_group.id | lgroup | integer | UNIQUE#1 NOT NULL |
Table: asset.copy_location_order
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
asset.copy_location.id | location | integer | UNIQUE#1 NOT NULL |
actor.org_unit.id | org | integer | UNIQUE#1 NOT NULL |
position | integer | NOT NULL |
Table: asset.copy_note
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
owning_copy | bigint | NOT NULL | |
actor.usr.id | creator | bigint | NOT NULL |
create_date | timestamp with time zone | DEFAULT now() | |
pub | boolean | NOT NULL DEFAULT false | |
title | text | NOT NULL | |
value | text | NOT NULL |
Table: asset.copy_part_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
target_copy | bigint | NOT NULL | |
biblio.monograph_part.id | part | integer | NOT NULL |
Table: asset.copy_tag
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
config.copy_tag_type.code | tag_type | text | |
label | text | NOT NULL | |
value | text | NOT NULL | |
index_vector | tsvector | NOT NULL | |
staff_note | text | ||
pub | boolean | DEFAULT true | |
actor.org_unit.id | owner | integer | NOT NULL |
url | text |
Tables referencing this one via Foreign Key Constraints:
asset_copy_tag_index_vector_idx index_vector asset_copy_tag_label_idx label asset_copy_tag_label_lower_idx lowercase(label) asset_copy_tag_owner_idx owner asset_copy_tag_tag_type_idx tag_typeTable: asset.copy_tag_copy_map
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
copy | bigint | ||
asset.copy_tag.id | tag | integer |
Table: asset.copy_template
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | owning_lib | integer | NOT NULL |
actor.usr.id | creator | bigint | NOT NULL |
actor.usr.id | editor | bigint | NOT NULL |
create_date | timestamp with time zone | DEFAULT now() | |
edit_date | timestamp with time zone | DEFAULT now() | |
name | text | NOT NULL | |
actor.org_unit.id | circ_lib | integer | |
config.copy_status.id | status | integer | |
asset.copy_location.id | location | integer | |
loan_duration | integer | ||
fine_level | integer | ||
age_protect | integer | ||
circulate | boolean | ||
deposit | boolean | ||
ref | boolean | ||
holdable | boolean | ||
deposit_amount | numeric(6,2) | ||
price | numeric(8,2) | ||
circ_modifier | text | ||
circ_as_type | text | ||
alert_message | text | ||
opac_visible | boolean | ||
config.floating_group.id | floating | integer | |
mint_condition | boolean |
Name | Constraint |
---|---|
valid_fine_level | CHECK (((fine_level IS NULL) OR (loan_duration = ANY (ARRAY[1, 2, 3])))) |
valid_loan_duration | CHECK (((loan_duration IS NULL) OR (loan_duration = ANY (ARRAY[1, 2, 3])))) |
Tables referencing this one via Foreign Key Constraints:
Table: asset.copy_vis_attr_cache
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
record | bigint | NOT NULL | |
target_copy | bigint | NOT NULL | |
vis_attr_vector | integer[] |
Table: asset.course_module_course
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | NOT NULL | |
course_number | text | NOT NULL | |
section_number | text | ||
actor.org_unit.id | owning_lib | integer | |
is_archived | boolean | DEFAULT false |
Tables referencing this one via Foreign Key Constraints:
Table: asset.course_module_course_materials
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
asset.course_module_course.id | course | integer | UNIQUE#1 NOT NULL |
asset.copy.id | item | integer | UNIQUE#1 |
relationship | text | ||
biblio.record_entry.id | record | integer | UNIQUE#1 |
temporary_record | boolean | ||
asset.copy_location.id | original_location | integer | |
config.copy_status.id | original_status | integer | |
config.circ_modifier.code | original_circ_modifier | text | |
asset.call_number.id | original_callnumber | integer | |
actor.org_unit.id | original_circ_lib | integer |
Table: asset.course_module_course_users
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
asset.course_module_course.id | course | integer | NOT NULL |
actor.usr.id | usr | integer | NOT NULL |
asset.course_module_role.id | usr_role | integer |
Table: asset.course_module_role
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE NOT NULL | |
is_public | boolean | NOT NULL DEFAULT false |
Tables referencing this one via Foreign Key Constraints:
Table: asset.course_module_term
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE#1 NOT NULL | |
actor.org_unit.id | owning_lib | integer | UNIQUE#1 |
start_date | timestamp with time zone | ||
end_date | timestamp with time zone |
Tables referencing this one via Foreign Key Constraints:
Table: asset.course_module_term_course_map
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
asset.course_module_term.id | term | integer | NOT NULL |
asset.course_module_course.id | course | integer | NOT NULL |
View: asset.latest_inventory
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
inventory_workstation | integer | ||
inventory_date | timestamp with time zone | ||
copy | bigint |
SELECT DISTINCT ON (copy_inventory.copy) copy_inventory.id , copy_inventory.inventory_workstation , copy_inventory.inventory_date , copy_inventory.copy FROM asset.copy_inventory ORDER BY copy_inventory.copy , copy_inventory.inventory_date DESC;
Table: asset.stat_cat
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | owner | integer | UNIQUE#1 NOT NULL |
opac_visible | boolean | NOT NULL DEFAULT false | |
name | text | UNIQUE#1 NOT NULL | |
required | boolean | NOT NULL DEFAULT false | |
asset.stat_cat_sip_fields.field | sip_field | character(2) | |
sip_format | text | ||
checkout_archive | boolean | NOT NULL DEFAULT false |
Tables referencing this one via Foreign Key Constraints:
Table: asset.stat_cat_entry
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
asset.stat_cat.id | stat_cat | integer | UNIQUE#1 NOT NULL |
actor.org_unit.id | owner | integer | UNIQUE#1 NOT NULL |
value | text | UNIQUE#1 NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: asset.stat_cat_entry_copy_map
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
asset.stat_cat.id | stat_cat | integer | UNIQUE#1 NOT NULL |
asset.stat_cat_entry.id | stat_cat_entry | integer | NOT NULL |
owning_copy | bigint | UNIQUE#1 NOT NULL |
Table: asset.stat_cat_entry_transparency_map
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
stat_cat | integer | UNIQUE#1 NOT NULL | |
stat_cat_entry | integer | NOT NULL | |
owning_transparency | integer | UNIQUE#1 NOT NULL |
Table: asset.stat_cat_sip_fields
Asset Statistical Category SIP Fields Contains the list of valid SIP Field identifiers for Statistical Categories.
F-Key | Name | Type | Description |
---|---|---|---|
field | character(2) | PRIMARY KEY | |
name | text | NOT NULL | |
one_only | boolean | NOT NULL DEFAULT false |
Tables referencing this one via Foreign Key Constraints:
Table: asset.uri
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
href | text | NOT NULL | |
label | text | ||
use_restriction | text | ||
active | boolean | NOT NULL DEFAULT true |
Tables referencing this one via Foreign Key Constraints:
Table: asset.uri_call_number_map
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
asset.uri.id | uri | integer | UNIQUE#1 NOT NULL |
asset.call_number.id | call_number | integer | UNIQUE#1 NOT NULL |
Function: asset.acp_created()
Returns: trigger
Language: PLPGSQL
BEGIN IF NEW.active_date IS NULL AND NEW.status IN (SELECT id FROM config.copy_status WHERE copy_active = true) THEN NEW.active_date := now(); END IF; IF NEW.status_changed_time IS NULL THEN NEW.status_changed_time := now(); END IF; RETURN NEW; END;
Function: asset.acp_location_fixer()
Returns: trigger
Language: PLPGSQL
DECLARE new_copy_location INT; BEGIN IF (TG_OP = 'UPDATE') THEN IF NEW.location = OLD.location AND NEW.call_number = OLD.call_number AND NEW.circ_lib = OLD.circ_lib THEN RETURN NEW; END IF; END IF; SELECT INTO new_copy_location acpl.id FROM asset.copy_location acpl JOIN actor.org_unit_ancestors_distance((SELECT owning_lib FROM asset.call_number WHERE id = NEW.call_number)) aouad ON acpl.owning_lib = aouad.id WHERE deleted IS FALSE AND name = (SELECT name FROM asset.copy_location WHERE id = NEW.location) ORDER BY distance LIMIT 1; IF new_copy_location IS NULL THEN SELECT INTO new_copy_location acpl.id FROM asset.copy_location acpl JOIN actor.org_unit_ancestors_distance(NEW.circ_lib) aouad ON acpl.owning_lib = aouad.id WHERE deleted IS FALSE AND name = (SELECT name FROM asset.copy_location WHERE id = NEW.location) ORDER BY distance LIMIT 1; END IF; IF new_copy_location IS NOT NULL THEN NEW.location = new_copy_location; END IF; RETURN NEW; END;
Function: asset.acp_status_changed()
Returns: trigger
Language: PLPGSQL
BEGIN IF NEW.status <> OLD.status AND NOT (NEW.status = 0 AND OLD.status = 7) THEN NEW.status_changed_time := now(); IF NEW.active_date IS NULL AND NEW.status IN (SELECT id FROM config.copy_status WHERE copy_active = true) THEN NEW.active_date := now(); END IF; END IF; RETURN NEW; END;
Function: asset.all_visible_flags()
Returns: text
Language: SQL
SELECT '(' || STRING_AGG(search.calculate_visibility_attribute(1 << x, 'copy_flags')::TEXT,'&') || ')' FROM GENERATE_SERIES(0,0) AS x; -- increment as new flags are added.
Function: asset.autogenerate_placeholder_barcode()
Returns: trigger
Language: PLPGSQL
BEGIN IF NEW.barcode LIKE '@@%' THEN NEW.barcode := '@@' || NEW.id; END IF; RETURN NEW; END;
Function: asset.bib_source_default()
Returns: text
Language: SQL
SELECT '(' || STRING_AGG(search.calculate_visibility_attribute(id, 'bib_source')::TEXT,'|') || ')' FROM config.bib_source WHERE transcendant;
Function: asset.cache_copy_visibility()
Returns: trigger
Language: PLPGSQL
DECLARE ocn asset.call_number%ROWTYPE; ncn asset.call_number%ROWTYPE; cid BIGINT; dobib BOOL; BEGIN SELECT enabled = FALSE INTO dobib FROM config.internal_flag WHERE name = 'ingest.reingest.force_on_same_marc'; IF TG_TABLE_NAME = 'peer_bib_copy_map' THEN -- Only needs ON INSERT OR DELETE, so handle separately IF TG_OP = 'INSERT' THEN INSERT INTO asset.copy_vis_attr_cache (record, target_copy, vis_attr_vector) VALUES ( NEW.peer_record, NEW.target_copy, asset.calculate_copy_visibility_attribute_set(NEW.target_copy) ); RETURN NEW; ELSIF TG_OP = 'DELETE' THEN DELETE FROM asset.copy_vis_attr_cache WHERE record = OLD.peer_record AND target_copy = OLD.target_copy; RETURN OLD; END IF; END IF; IF TG_OP = 'INSERT' THEN -- Handles ON INSERT. ON UPDATE is below. IF TG_TABLE_NAME IN ('copy', 'unit') THEN SELECT * INTO ncn FROM asset.call_number cn WHERE id = NEW.call_number; INSERT INTO asset.copy_vis_attr_cache (record, target_copy, vis_attr_vector) VALUES ( ncn.record, NEW.id, asset.calculate_copy_visibility_attribute_set(NEW.id) ); ELSIF TG_TABLE_NAME = 'record_entry' THEN NEW.vis_attr_vector := biblio.calculate_bib_visibility_attribute_set(NEW.id, NEW.source, TRUE); ELSIF TG_TABLE_NAME = 'call_number' AND NEW.label = '##URI##' AND dobib THEN -- New located URI UPDATE biblio.record_entry SET vis_attr_vector = biblio.calculate_bib_visibility_attribute_set(NEW.record) WHERE id = NEW.record; END IF; RETURN NEW; END IF; -- handle items first, since with circulation activity -- their statuses change frequently IF TG_TABLE_NAME IN ('copy', 'unit') THEN -- This handles ON UPDATE OR DELETE. ON INSERT above IF TG_OP = 'DELETE' THEN -- Shouldn't get here, normally DELETE FROM asset.copy_vis_attr_cache WHERE target_copy = OLD.id; RETURN OLD; END IF; SELECT * INTO ncn FROM asset.call_number cn WHERE id = NEW.call_number; IF OLD.deleted <> NEW.deleted THEN IF NEW.deleted THEN DELETE FROM asset.copy_vis_attr_cache WHERE target_copy = OLD.id; ELSE INSERT INTO asset.copy_vis_attr_cache (record, target_copy, vis_attr_vector) VALUES ( ncn.record, NEW.id, asset.calculate_copy_visibility_attribute_set(NEW.id) ); END IF; RETURN NEW; ELSIF OLD.location <> NEW.location OR OLD.status <> NEW.status OR OLD.opac_visible <> NEW.opac_visible OR OLD.circ_lib <> NEW.circ_lib OR OLD.call_number <> NEW.call_number THEN IF OLD.call_number <> NEW.call_number THEN -- Special check since it's more expensive than the next branch SELECT * INTO ocn FROM asset.call_number cn WHERE id = OLD.call_number; IF ncn.record <> ocn.record THEN -- We have to use a record-specific WHERE clause -- to avoid modifying the entries for peer-bib copies. UPDATE asset.copy_vis_attr_cache SET target_copy = NEW.id, record = ncn.record WHERE target_copy = OLD.id AND record = ocn.record; END IF; ELSE -- Any of these could change visibility, but -- we'll save some queries and not try to calculate -- the change directly. We want to update peer-bib -- entries in this case, unlike above. UPDATE asset.copy_vis_attr_cache SET target_copy = NEW.id, vis_attr_vector = asset.calculate_copy_visibility_attribute_set(NEW.id) WHERE target_copy = OLD.id; END IF; END IF; ELSIF TG_TABLE_NAME = 'call_number' THEN IF TG_OP = 'DELETE' AND OLD.label = '##URI##' AND dobib THEN -- really deleted located URI, if the delete protection rule is disabled... UPDATE biblio.record_entry SET vis_attr_vector = biblio.calculate_bib_visibility_attribute_set(OLD.record) WHERE id = OLD.record; RETURN OLD; END IF; IF OLD.label = '##URI##' AND dobib THEN -- Located URI IF OLD.deleted <> NEW.deleted OR OLD.record <> NEW.record OR OLD.owning_lib <> NEW.owning_lib THEN UPDATE biblio.record_entry SET vis_attr_vector = biblio.calculate_bib_visibility_attribute_set(NEW.record) WHERE id = NEW.record; IF OLD.record <> NEW.record THEN -- maybe on merge? UPDATE biblio.record_entry SET vis_attr_vector = biblio.calculate_bib_visibility_attribute_set(OLD.record) WHERE id = OLD.record; END IF; END IF; ELSIF OLD.record <> NEW.record OR OLD.owning_lib <> NEW.owning_lib THEN UPDATE asset.copy_vis_attr_cache SET record = NEW.record, vis_attr_vector = asset.calculate_copy_visibility_attribute_set(target_copy) WHERE target_copy IN (SELECT id FROM asset.copy WHERE call_number = NEW.id) AND record = OLD.record; END IF; ELSIF TG_TABLE_NAME = 'record_entry' AND OLD.source IS DISTINCT FROM NEW.source THEN -- Only handles ON UPDATE, INSERT above NEW.vis_attr_vector := biblio.calculate_bib_visibility_attribute_set(NEW.id, NEW.source, TRUE); END IF; RETURN NEW; END;
Function: asset.calculate_copy_visibility_attribute_set(copy_id bigint)
Returns: integer[]
Language: PLPGSQL
DECLARE copy_row asset.copy%ROWTYPE; lgroup_map asset.copy_location_group_map%ROWTYPE; attr_set INT[] := '{}'::INT[]; BEGIN SELECT * INTO copy_row FROM asset.copy WHERE id = copy_id; attr_set := attr_set || search.calculate_visibility_attribute(copy_row.opac_visible::INT, 'copy_flags'); attr_set := attr_set || search.calculate_visibility_attribute(copy_row.circ_lib, 'circ_lib'); attr_set := attr_set || search.calculate_visibility_attribute(copy_row.status, 'status'); attr_set := attr_set || search.calculate_visibility_attribute(copy_row.location, 'location'); SELECT ARRAY_APPEND( attr_set, search.calculate_visibility_attribute(owning_lib, 'owning_lib') ) INTO attr_set FROM asset.call_number WHERE id = copy_row.call_number; FOR lgroup_map IN SELECT * FROM asset.copy_location_group_map WHERE location = copy_row.location LOOP attr_set := attr_set || search.calculate_visibility_attribute(lgroup_map.lgroup, 'location_group'); END LOOP; RETURN attr_set; END;
Function: asset.check_delete_copy_location(acpl_id integer)
Returns: void
Language: PLPGSQL
BEGIN PERFORM TRUE FROM asset.copy WHERE location = acpl_id AND NOT deleted LIMIT 1; IF FOUND THEN RAISE EXCEPTION 'Copy location % contains active copies and cannot be deleted', acpl_id; END IF; END;
Function: asset.circ_lib_default()
Returns: text
Language: SQL
SELECT * FROM asset.invisible_orgs('circ_lib');
Function: asset.copy_may_float_to_inventory_workstation()
Returns: trigger
Language: PLPGSQL
DECLARE copy asset.copy%ROWTYPE; workstation actor.workstation%ROWTYPE; BEGIN SELECT * INTO copy FROM asset.copy WHERE id = NEW.copy; IF FOUND THEN SELECT * INTO workstation FROM actor.workstation WHERE id = NEW.inventory_workstation; IF FOUND THEN IF copy.floating IS NULL THEN IF copy.circ_lib <> workstation.owning_lib THEN RAISE EXCEPTION 'Inventory workstation owning lib (%) does not match copy circ lib (%).', workstation.owning_lib, copy.circ_lib; END IF; ELSE IF NOT evergreen.can_float(copy.floating, copy.circ_lib, workstation.owning_lib) THEN RAISE EXCEPTION 'Copy (%) cannot float to inventory workstation owning lib (%).', copy.id, workstation.owning_lib; END IF; END IF; END IF; END IF; RETURN NEW; END;
Function: asset.copy_state(cid bigint)
Returns: text
Language: PLPGSQL
DECLARE last_circ_stop TEXT; the_copy asset.copy%ROWTYPE; BEGIN SELECT * INTO the_copy FROM asset.copy WHERE id = cid; IF NOT FOUND THEN RETURN NULL; END IF; IF the_copy.status = 3 THEN -- Lost RETURN 'LOST'; ELSIF the_copy.status = 4 THEN -- Missing RETURN 'MISSING'; ELSIF the_copy.status = 14 THEN -- Damaged RETURN 'DAMAGED'; ELSIF the_copy.status = 17 THEN -- Lost and paid RETURN 'LOST_AND_PAID'; END IF; SELECT stop_fines INTO last_circ_stop FROM action.circulation WHERE target_copy = cid AND checkin_time IS NULL ORDER BY xact_start DESC LIMIT 1; IF FOUND THEN IF last_circ_stop IN ( 'CLAIMSNEVERCHECKEDOUT', 'CLAIMSRETURNED', 'LONGOVERDUE' ) THEN RETURN last_circ_stop; END IF; END IF; RETURN 'NORMAL'; END;
Function: asset.invisible_orgs(otype text)
Returns: text
Language: SQL
SELECT '!(' || STRING_AGG(search.calculate_visibility_attribute(id, $1)::TEXT,'|') || ')' FROM actor.org_unit WHERE NOT opac_visible;
Function: asset.label_normalizer()
Returns: trigger
Language: PLPGSQL
DECLARE sortkey TEXT := ''; BEGIN sortkey := NEW.label_sortkey; IF NEW.label_class IS NULL THEN NEW.label_class := COALESCE( ( SELECT substring(value from E'\\d+')::integer FROM actor.org_unit_ancestor_setting('cat.default_classification_scheme', NEW.owning_lib) ), 1 ); END IF; EXECUTE 'SELECT ' || acnc.normalizer || '(' || quote_literal( NEW.label ) || ')' FROM asset.call_number_class acnc WHERE acnc.id = NEW.label_class INTO sortkey; NEW.label_sortkey = sortkey; RETURN NEW; END;
Function: asset.label_normalizer_dewey(text)
Returns: text
Language: PLPERLU
# Derived from the Koha C4::ClassSortRoutine::Dewey module # Copyright (C) 2007 LibLime # Licensed under the GPL v2 or later use strict; use warnings; my $init = uc(shift); $init =~ s/^\s+//; $init =~ s/\s+$//; $init =~ s!/!!g; $init =~ s/^([\p{IsAlpha}]+)/$1 /; my @tokens = split /\.|\s+/, $init; my $digit_group_count = 0; my $first_digit_group_idx; for (my $i = 0; $i <= $#tokens; $i++) { if ($tokens[$i] =~ /^\d+$/) { $digit_group_count++; if ($digit_group_count == 1) { $first_digit_group_idx = $i; } if (2 == $digit_group_count) { $tokens[$i] = sprintf("%-15.15s", $tokens[$i]); $tokens[$i] =~ tr/ /0/; } } } # Pad the first digit_group if there was only one if (1 == $digit_group_count) { $tokens[$first_digit_group_idx] .= '_000000000000000' } my $key = join("_", @tokens); $key =~ s/[^\p{IsAlnum}_]//g; return $key;
Function: asset.label_normalizer_generic(text)
Returns: text
Language: PLPERLU
# Created after looking at the Koha C4::ClassSortRoutine::Generic module, # thus could probably be considered a derived work, although nothing was # directly copied - but to err on the safe side of providing attribution: # Copyright (C) 2007 LibLime # Copyright (C) 2011 Equinox Software, Inc (Steve Callendar) # Licensed under the GPL v2 or later use strict; use warnings; # Converts the callnumber to uppercase # Strips spaces from start and end of the call number # Converts anything other than letters, digits, and periods into spaces # Collapses multiple spaces into a single underscore my $callnum = uc(shift); $callnum =~ s/^\s//g; $callnum =~ s/\s$//g; # NOTE: this previously used underscores, but this caused sorting issues # for the "before" half of page 0 on CN browse, sorting CNs containing a # decimal before "whole number" CNs $callnum =~ s/[^A-Z0-9_.]/ /g; $callnum =~ s/ {2,}/ /g; return $callnum;
Function: asset.label_normalizer_lc(text)
Returns: text
Language: PLPERLU
use strict; use warnings; # Library::CallNumber::LC is currently hosted at http://code.google.com/p/library-callnumber-lc/ # The author hopes to upload it to CPAN some day, which would make our lives easier use Library::CallNumber::LC; my $callnum = Library::CallNumber::LC->new(shift); return $callnum->normalize();
Function: asset.location_default()
Returns: text
Language: SQL
SELECT '!(' || STRING_AGG(search.calculate_visibility_attribute(id, 'location')::TEXT,'|') || ')' FROM asset.copy_location WHERE NOT opac_visible;
Function: asset.location_group_default()
Returns: text
Language: SQL
SELECT '!()'::TEXT; -- For now, as there's no way to cause a location group to hide all copies. /* SELECT '!(' || STRING_AGG(search.calculate_visibility_attribute(id, 'location_group')::TEXT,'|') || ')' FROM asset.copy_location_group WHERE NOT opac_visible; */
Function: asset.luri_org_default()
Returns: text
Language: SQL
SELECT * FROM asset.invisible_orgs('luri_org');
Function: asset.merge_record_assets(source_record bigint, target_record bigint)
Returns: integer
Language: PLPGSQL
DECLARE moved_objects INT := 0; source_cn asset.call_number%ROWTYPE; target_cn asset.call_number%ROWTYPE; metarec metabib.metarecord%ROWTYPE; hold action.hold_request%ROWTYPE; ser_rec serial.record_entry%ROWTYPE; ser_sub serial.subscription%ROWTYPE; acq_lineitem acq.lineitem%ROWTYPE; acq_request acq.user_request%ROWTYPE; booking booking.resource_type%ROWTYPE; source_part biblio.monograph_part%ROWTYPE; target_part biblio.monograph_part%ROWTYPE; multi_home biblio.peer_bib_copy_map%ROWTYPE; uri_count INT := 0; counter INT := 0; uri_datafield TEXT; uri_text TEXT := ''; BEGIN -- we don't merge bib -1 IF target_record = -1 OR source_record = -1 THEN RETURN 0; END IF; -- move any 856 entries on records that have at least one MARC-mapped URI entry SELECT INTO uri_count COUNT(*) FROM asset.uri_call_number_map m JOIN asset.call_number cn ON (m.call_number = cn.id) WHERE cn.record = source_record; IF uri_count > 0 THEN -- This returns more nodes than you might expect: -- 7 instead of 1 for an 856 with $u $y $9 SELECT COUNT(*) INTO counter FROM oils_xpath_table( 'id', 'marc', 'biblio.record_entry', '//*[@tag="856"]', 'id=' || source_record ) as t(i int,c text); FOR i IN 1 .. counter LOOP SELECT '<datafield xmlns="http://www.loc.gov/MARC21/slim"' || ' tag="856"' || ' ind1="' || FIRST(ind1) || '"' || ' ind2="' || FIRST(ind2) || '">' || STRING_AGG( '<subfield code="' || subfield || '">' || regexp_replace( regexp_replace( regexp_replace(data,'&','&','g'), '>', '>', 'g' ), '<', '<', 'g' ) || '</subfield>', '' ) || '</datafield>' INTO uri_datafield FROM oils_xpath_table( 'id', 'marc', 'biblio.record_entry', '//*[@tag="856"][position()=' || i || ']/@ind1|' || '//*[@tag="856"][position()=' || i || ']/@ind2|' || '//*[@tag="856"][position()=' || i || ']/*/@code|' || '//*[@tag="856"][position()=' || i || ']/*[@code]', 'id=' || source_record ) as t(id int,ind1 text, ind2 text,subfield text,data text); -- As most of the results will be NULL, protect against NULLifying -- the valid content that we do generate uri_text := uri_text || COALESCE(uri_datafield, ''); END LOOP; IF uri_text <> '' THEN UPDATE biblio.record_entry SET marc = regexp_replace(marc,'(</[^>]*record>)', uri_text || E'\\1') WHERE id = target_record; END IF; END IF; -- Find and move metarecords to the target record SELECT INTO metarec * FROM metabib.metarecord WHERE master_record = source_record; IF FOUND THEN UPDATE metabib.metarecord SET master_record = target_record, mods = NULL WHERE id = metarec.id; moved_objects := moved_objects + 1; END IF; -- Find call numbers attached to the source ... FOR source_cn IN SELECT * FROM asset.call_number WHERE record = source_record LOOP SELECT INTO target_cn * FROM asset.call_number WHERE label = source_cn.label AND prefix = source_cn.prefix AND suffix = source_cn.suffix AND owning_lib = source_cn.owning_lib AND record = target_record AND NOT deleted; -- ... and if there's a conflicting one on the target ... IF FOUND THEN -- ... move the copies to that, and ... UPDATE asset.copy SET call_number = target_cn.id WHERE call_number = source_cn.id; -- ... move V holds to the move-target call number FOR hold IN SELECT * FROM action.hold_request WHERE target = source_cn.id AND hold_type = 'V' LOOP UPDATE action.hold_request SET target = target_cn.id WHERE id = hold.id; moved_objects := moved_objects + 1; END LOOP; UPDATE asset.call_number SET deleted = TRUE WHERE id = source_cn.id; -- ... if not ... ELSE -- ... just move the call number to the target record UPDATE asset.call_number SET record = target_record WHERE id = source_cn.id; END IF; moved_objects := moved_objects + 1; END LOOP; -- Find T holds targeting the source record ... FOR hold IN SELECT * FROM action.hold_request WHERE target = source_record AND hold_type = 'T' LOOP -- ... and move them to the target record UPDATE action.hold_request SET target = target_record WHERE id = hold.id; moved_objects := moved_objects + 1; END LOOP; -- Find serial records targeting the source record ... FOR ser_rec IN SELECT * FROM serial.record_entry WHERE record = source_record LOOP -- ... and move them to the target record UPDATE serial.record_entry SET record = target_record WHERE id = ser_rec.id; moved_objects := moved_objects + 1; END LOOP; -- Find serial subscriptions targeting the source record ... FOR ser_sub IN SELECT * FROM serial.subscription WHERE record_entry = source_record LOOP -- ... and move them to the target record UPDATE serial.subscription SET record_entry = target_record WHERE id = ser_sub.id; moved_objects := moved_objects + 1; END LOOP; -- Find booking resource types targeting the source record ... FOR booking IN SELECT * FROM booking.resource_type WHERE record = source_record LOOP -- ... and move them to the target record UPDATE booking.resource_type SET record = target_record WHERE id = booking.id; moved_objects := moved_objects + 1; END LOOP; -- Find acq lineitems targeting the source record ... FOR acq_lineitem IN SELECT * FROM acq.lineitem WHERE eg_bib_id = source_record LOOP -- ... and move them to the target record UPDATE acq.lineitem SET eg_bib_id = target_record WHERE id = acq_lineitem.id; moved_objects := moved_objects + 1; END LOOP; -- Find acq user purchase requests targeting the source record ... FOR acq_request IN SELECT * FROM acq.user_request WHERE eg_bib = source_record LOOP -- ... and move them to the target record UPDATE acq.user_request SET eg_bib = target_record WHERE id = acq_request.id; moved_objects := moved_objects + 1; END LOOP; -- Find parts attached to the source ... FOR source_part IN SELECT * FROM biblio.monograph_part WHERE record = source_record LOOP SELECT INTO target_part * FROM biblio.monograph_part WHERE label = source_part.label AND record = target_record; -- ... and if there's a conflicting one on the target ... IF FOUND THEN -- ... move the copy-part maps to that, and ... UPDATE asset.copy_part_map SET part = target_part.id WHERE part = source_part.id; -- ... move P holds to the move-target part FOR hold IN SELECT * FROM action.hold_request WHERE target = source_part.id AND hold_type = 'P' LOOP UPDATE action.hold_request SET target = target_part.id WHERE id = hold.id; moved_objects := moved_objects + 1; END LOOP; -- ... if not ... ELSE -- ... just move the part to the target record UPDATE biblio.monograph_part SET record = target_record WHERE id = source_part.id; END IF; moved_objects := moved_objects + 1; END LOOP; -- Find multi_home items attached to the source ... FOR multi_home IN SELECT * FROM biblio.peer_bib_copy_map WHERE peer_record = source_record LOOP -- ... and move them to the target record UPDATE biblio.peer_bib_copy_map SET peer_record = target_record WHERE id = multi_home.id; moved_objects := moved_objects + 1; END LOOP; -- And delete mappings where the item's home bib was merged with the peer bib DELETE FROM biblio.peer_bib_copy_map WHERE peer_record = ( SELECT (SELECT record FROM asset.call_number WHERE id = call_number) FROM asset.copy WHERE id = target_copy ); -- Apply merge tracking UPDATE biblio.record_entry SET merge_date = NOW() WHERE id = target_record; UPDATE biblio.record_entry SET merge_date = NOW(), merged_to = target_record WHERE id = source_record; -- replace book bag entries of source_record with target_record UPDATE container.biblio_record_entry_bucket_item SET target_biblio_record_entry = target_record WHERE bucket IN (SELECT id FROM container.biblio_record_entry_bucket WHERE btype = 'bookbag') AND target_biblio_record_entry = source_record; -- move over record notes UPDATE biblio.record_note SET record = target_record, value = CONCAT(value,'; note merged from ',source_record::TEXT) WHERE record = source_record AND NOT deleted; -- add note to record merge INSERT INTO biblio.record_note (record, value) VALUES (target_record,CONCAT('record ',source_record::TEXT,' merged on ',NOW()::TEXT)); -- Finally, "delete" the source record UPDATE biblio.record_entry SET active = FALSE WHERE id = source_record; DELETE FROM biblio.record_entry WHERE id = source_record; -- That's all, folks! RETURN moved_objects; END;
Function: asset.metarecord_copy_count(transcendant integer, unshadow bigint, available boolean)
Returns: SET OF record
Language: PLPGSQL
BEGIN IF staff IS TRUE THEN IF place > 0 THEN RETURN QUERY SELECT * FROM asset.staff_ou_metarecord_copy_count( place, rid ); ELSE RETURN QUERY SELECT * FROM asset.staff_lasso_metarecord_copy_count( -place, rid ); END IF; ELSE IF place > 0 THEN RETURN QUERY SELECT * FROM asset.opac_ou_metarecord_copy_count( place, rid ); ELSE RETURN QUERY SELECT * FROM asset.opac_lasso_metarecord_copy_count( -place, rid ); END IF; END IF; RETURN; END;
Function: asset.metarecord_has_holdable_copy(ou bigint, rid integer)
Returns: boolean
Language: PLPGSQL
BEGIN PERFORM 1 FROM asset.copy acp JOIN asset.call_number acn ON acp.call_number = acn.id JOIN asset.copy_location acpl ON acp.location = acpl.id JOIN config.copy_status ccs ON acp.status = ccs.id JOIN metabib.metarecord_source_map mmsm ON acn.record = mmsm.source WHERE mmsm.metarecord = rid AND acp.holdable = true AND acpl.holdable = true AND ccs.holdable = true AND acp.deleted = false AND acpl.deleted = false AND acp.circ_lib IN (SELECT id FROM actor.org_unit_descendants(COALESCE($2,(SELECT id FROM evergreen.org_top())))) LIMIT 1; IF FOUND THEN RETURN true; END IF; RETURN FALSE; END;
Function: asset.normalize_affix_sortkey()
Returns: trigger
Language: PLPGSQL
BEGIN NEW.label_sortkey := REGEXP_REPLACE( evergreen.lpad_number_substrings( naco_normalize(NEW.label), '0', 10 ), E'\\s+', '', 'g' ); RETURN NEW; END;
Function: asset.opac_lasso_metarecord_copy_count(transcendant integer, unshadow bigint)
Returns: SET OF record
Language: PLPGSQL
DECLARE ans RECORD; trans INT; BEGIN SELECT 1 INTO trans FROM biblio.record_entry b JOIN config.bib_source src ON (b.source = src.id) JOIN metabib.metarecord_source_map m ON (m.source = b.id) WHERE src.transcendant AND m.metarecord = rid; FOR ans IN SELECT u.org_unit AS id FROM actor.org_lasso_map AS u WHERE lasso = i_lasso LOOP RETURN QUERY WITH org_list AS (SELECT ARRAY_AGG(id)::BIGINT[] AS orgs FROM actor.org_unit_descendants(ans.id) x), available_statuses AS (SELECT ARRAY_AGG(id) AS ids FROM config.copy_status WHERE is_available), mask AS (SELECT c_attrs FROM asset.patron_default_visibility_mask() x) SELECT -1, ans.id, COUNT( av.id ), SUM( (cp.status = ANY (available_statuses.ids))::INT ), COUNT( av.id ), trans FROM mask, org_list, available_statuses, asset.copy_vis_attr_cache av JOIN asset.copy cp ON (cp.id = av.target_copy) JOIN metabib.metarecord_source_map m ON (m.metarecord = rid AND m.source = av.record) WHERE cp.circ_lib = ANY (org_list.orgs) AND av.vis_attr_vector @@ mask.c_attrs::query_int GROUP BY 1,2,6; IF NOT FOUND THEN RETURN QUERY SELECT ans.depth, ans.id, 0::BIGINT, 0::BIGINT, 0::BIGINT, trans; END IF; END LOOP; RETURN; END;
Function: asset.opac_lasso_record_copy_count(transcendant integer, unshadow bigint)
Returns: SET OF record
Language: PLPGSQL
DECLARE ans RECORD; trans INT; BEGIN SELECT 1 INTO trans FROM biblio.record_entry b JOIN config.bib_source src ON (b.source = src.id) WHERE src.transcendant AND b.id = rid; FOR ans IN SELECT u.org_unit AS id FROM actor.org_lasso_map AS u WHERE lasso = i_lasso LOOP RETURN QUERY WITH org_list AS (SELECT ARRAY_AGG(id)::BIGINT[] AS orgs FROM actor.org_unit_descendants(ans.id) x), available_statuses AS (SELECT ARRAY_AGG(id) AS ids FROM config.copy_status WHERE is_available), mask AS (SELECT c_attrs FROM asset.patron_default_visibility_mask() x) SELECT -1, ans.id, COUNT( av.id ), SUM( (cp.status = ANY (available_statuses.ids))::INT ), COUNT( av.id ), trans FROM mask, org_list, asset.copy_vis_attr_cache av JOIN asset.copy cp ON (cp.id = av.target_copy AND av.record = rid) WHERE cp.circ_lib = ANY (org_list.orgs) AND av.vis_attr_vector @@ mask.c_attrs::query_int GROUP BY 1,2,6; IF NOT FOUND THEN RETURN QUERY SELECT -1, ans.id, 0::BIGINT, 0::BIGINT, 0::BIGINT, trans; END IF; END LOOP; RETURN; END;
Function: asset.opac_ou_metarecord_copy_count(transcendant integer, unshadow bigint)
Returns: SET OF record
Language: PLPGSQL
DECLARE ans RECORD; trans INT; BEGIN SELECT 1 INTO trans FROM biblio.record_entry b JOIN config.bib_source src ON (b.source = src.id) JOIN metabib.metarecord_source_map m ON (m.source = b.id) WHERE src.transcendant AND m.metarecord = rid; FOR ans IN SELECT u.id, t.depth FROM actor.org_unit_ancestors(org) AS u JOIN actor.org_unit_type t ON (u.ou_type = t.id) LOOP RETURN QUERY WITH org_list AS (SELECT ARRAY_AGG(id)::BIGINT[] AS orgs FROM actor.org_unit_descendants(ans.id) x), available_statuses AS (SELECT ARRAY_AGG(id) AS ids FROM config.copy_status WHERE is_available), mask AS (SELECT c_attrs FROM asset.patron_default_visibility_mask() x) SELECT ans.depth, ans.id, COUNT( av.id ), SUM( (cp.status = ANY (available_statuses.ids))::INT ), COUNT( av.id ), trans FROM mask, org_list, available_statuses, asset.copy_vis_attr_cache av JOIN asset.copy cp ON (cp.id = av.target_copy) JOIN metabib.metarecord_source_map m ON (m.metarecord = rid AND m.source = av.record) WHERE cp.circ_lib = ANY (org_list.orgs) AND av.vis_attr_vector @@ mask.c_attrs::query_int GROUP BY 1,2,6; IF NOT FOUND THEN RETURN QUERY SELECT ans.depth, ans.id, 0::BIGINT, 0::BIGINT, 0::BIGINT, trans; END IF; END LOOP; RETURN; END;
Function: asset.opac_ou_record_copy_count(transcendant integer, unshadow bigint)
Returns: SET OF record
Language: PLPGSQL
DECLARE ans RECORD; trans INT; BEGIN SELECT 1 INTO trans FROM biblio.record_entry b JOIN config.bib_source src ON (b.source = src.id) WHERE src.transcendant AND b.id = rid; FOR ans IN SELECT u.id, t.depth FROM actor.org_unit_ancestors(org) AS u JOIN actor.org_unit_type t ON (u.ou_type = t.id) LOOP RETURN QUERY WITH org_list AS (SELECT ARRAY_AGG(id)::BIGINT[] AS orgs FROM actor.org_unit_descendants(ans.id) x), available_statuses AS (SELECT ARRAY_AGG(id) AS ids FROM config.copy_status WHERE is_available), mask AS (SELECT c_attrs FROM asset.patron_default_visibility_mask() x) SELECT ans.depth, ans.id, COUNT( av.id ), SUM( (cp.status = ANY (available_statuses.ids))::INT ), COUNT( av.id ), trans FROM mask, available_statuses, org_list, asset.copy_vis_attr_cache av JOIN asset.copy cp ON (cp.id = av.target_copy AND av.record = rid) JOIN asset.call_number cn ON (cp.call_number = cn.id AND not cn.deleted) WHERE cp.circ_lib = ANY (org_list.orgs) AND av.vis_attr_vector @@ mask.c_attrs::query_int GROUP BY 1,2,6; IF NOT FOUND THEN RETURN QUERY SELECT ans.depth, ans.id, 0::BIGINT, 0::BIGINT, 0::BIGINT, trans; END IF; END LOOP; RETURN; END;
Function: asset.owning_lib_default()
Returns: text
Language: SQL
SELECT * FROM asset.invisible_orgs('owning_lib');
Function: asset.patron_default_visibility_mask()
Returns: SET OF record
Language: PLPGSQL
DECLARE copy_flags TEXT; -- "c" attr owning_lib TEXT; -- "c" attr circ_lib TEXT; -- "c" attr status TEXT; -- "c" attr location TEXT; -- "c" attr location_group TEXT; -- "c" attr luri_org TEXT; -- "b" attr bib_sources TEXT; -- "b" attr bib_tests TEXT := ''; BEGIN copy_flags := asset.all_visible_flags(); -- Will always have at least one owning_lib := NULLIF(asset.owning_lib_default(),'!()'); circ_lib := NULLIF(asset.circ_lib_default(),'!()'); status := NULLIF(asset.status_default(),'!()'); location := NULLIF(asset.location_default(),'!()'); location_group := NULLIF(asset.location_group_default(),'!()'); -- LURIs will be handled at the perl layer directly -- luri_org := NULLIF(asset.luri_org_default(),'!()'); bib_sources := NULLIF(asset.bib_source_default(),'()'); IF luri_org IS NOT NULL AND bib_sources IS NOT NULL THEN bib_tests := '('||ARRAY_TO_STRING( ARRAY[luri_org,bib_sources], '|')||')&('||luri_org||')&'; ELSIF luri_org IS NOT NULL THEN bib_tests := luri_org || '&'; ELSIF bib_sources IS NOT NULL THEN bib_tests := bib_sources || '|'; END IF; RETURN QUERY SELECT bib_tests, '('||ARRAY_TO_STRING( ARRAY[copy_flags,owning_lib,circ_lib,status,location,location_group]::TEXT[], '&' )||')'; END;
Function: asset.record_copy_count(transcendant integer, unshadow bigint, available boolean)
Returns: SET OF record
Language: PLPGSQL
BEGIN IF staff IS TRUE THEN IF place > 0 THEN RETURN QUERY SELECT * FROM asset.staff_ou_record_copy_count( place, rid ); ELSE RETURN QUERY SELECT * FROM asset.staff_lasso_record_copy_count( -place, rid ); END IF; ELSE IF place > 0 THEN RETURN QUERY SELECT * FROM asset.opac_ou_record_copy_count( place, rid ); ELSE RETURN QUERY SELECT * FROM asset.opac_lasso_record_copy_count( -place, rid ); END IF; END IF; RETURN; END;
Function: asset.record_has_holdable_copy(ou bigint, rid integer)
Returns: boolean
Language: PLPGSQL
BEGIN PERFORM 1 FROM asset.copy acp JOIN asset.call_number acn ON acp.call_number = acn.id JOIN asset.copy_location acpl ON acp.location = acpl.id JOIN config.copy_status ccs ON acp.status = ccs.id WHERE acn.record = rid AND acp.holdable = true AND acpl.holdable = true AND ccs.holdable = true AND acp.deleted = false AND acpl.deleted = false AND acp.circ_lib IN (SELECT id FROM actor.org_unit_descendants(COALESCE($2,(SELECT id FROM evergreen.org_top())))) LIMIT 1; IF FOUND THEN RETURN true; END IF; RETURN FALSE; END;
Function: asset.set_copy_tag_value()
Returns: trigger
Language: PLPGSQL
BEGIN IF NEW.value IS NULL THEN NEW.value = NEW.label; END IF; RETURN NEW; END;
Function: asset.staff_lasso_metarecord_copy_count(transcendant integer, unshadow bigint)
Returns: SET OF record
Language: PLPGSQL
DECLARE ans RECORD; trans INT; BEGIN SELECT 1 INTO trans FROM biblio.record_entry b JOIN config.bib_source src ON (b.source = src.id) JOIN metabib.metarecord_source_map m ON (m.source = b.id) WHERE src.transcendant AND m.metarecord = rid; FOR ans IN SELECT u.org_unit AS id FROM actor.org_lasso_map AS u WHERE lasso = i_lasso LOOP RETURN QUERY SELECT -1, ans.id, COUNT( cp.id ), SUM( CASE WHEN cp.status IN (0,7,12) THEN 1 ELSE 0 END ), COUNT( cp.id ), trans FROM actor.org_unit_descendants(ans.id) d JOIN asset.copy cp ON (cp.circ_lib = d.id AND NOT cp.deleted) JOIN asset.call_number cn ON (cn.id = cp.call_number AND NOT cn.deleted) JOIN metabib.metarecord_source_map m ON (m.metarecord = rid AND m.source = cn.record) GROUP BY 1,2,6; IF NOT FOUND THEN RETURN QUERY SELECT ans.depth, ans.id, 0::BIGINT, 0::BIGINT, 0::BIGINT, trans; END IF; END LOOP; RETURN; END;
Function: asset.staff_lasso_record_copy_count(transcendant integer, unshadow bigint)
Returns: SET OF record
Language: PLPGSQL
DECLARE ans RECORD; trans INT; BEGIN SELECT 1 INTO trans FROM biblio.record_entry b JOIN config.bib_source src ON (b.source = src.id) WHERE src.transcendant AND b.id = rid; FOR ans IN SELECT u.org_unit AS id FROM actor.org_lasso_map AS u WHERE lasso = i_lasso LOOP RETURN QUERY SELECT -1, ans.id, COUNT( cp.id ), SUM( CASE WHEN cp.status IN (0,7,12) THEN 1 ELSE 0 END ), SUM( CASE WHEN cl.opac_visible AND cp.opac_visible THEN 1 ELSE 0 END), trans FROM actor.org_unit_descendants(ans.id) d JOIN asset.copy cp ON (cp.circ_lib = d.id AND NOT cp.deleted) JOIN asset.copy_location cl ON (cp.location = cl.id AND NOT cl.deleted) JOIN asset.call_number cn ON (cn.record = rid AND cn.id = cp.call_number AND NOT cn.deleted) GROUP BY 1,2,6; IF NOT FOUND THEN RETURN QUERY SELECT -1, ans.id, 0::BIGINT, 0::BIGINT, 0::BIGINT, trans; END IF; END LOOP; RETURN; END;
Function: asset.staff_ou_metarecord_copy_count(transcendant integer, unshadow bigint)
Returns: SET OF record
Language: PLPGSQL
DECLARE ans RECORD; trans INT; BEGIN SELECT 1 INTO trans FROM biblio.record_entry b JOIN config.bib_source src ON (b.source = src.id) JOIN metabib.metarecord_source_map m ON (m.source = b.id) WHERE src.transcendant AND m.metarecord = rid; FOR ans IN SELECT u.id, t.depth FROM actor.org_unit_ancestors(org) AS u JOIN actor.org_unit_type t ON (u.ou_type = t.id) LOOP RETURN QUERY SELECT ans.depth, ans.id, COUNT( cp.id ), SUM( CASE WHEN cp.status IN (0,7,12) THEN 1 ELSE 0 END ), COUNT( cp.id ), trans FROM actor.org_unit_descendants(ans.id) d JOIN asset.copy cp ON (cp.circ_lib = d.id AND NOT cp.deleted) JOIN asset.call_number cn ON (cn.id = cp.call_number AND NOT cn.deleted) JOIN metabib.metarecord_source_map m ON (m.metarecord = rid AND m.source = cn.record) GROUP BY 1,2,6; IF NOT FOUND THEN RETURN QUERY SELECT ans.depth, ans.id, 0::BIGINT, 0::BIGINT, 0::BIGINT, trans; END IF; END LOOP; RETURN; END;
Function: asset.staff_ou_record_copy_count(transcendant integer, unshadow bigint)
Returns: SET OF record
Language: PLPGSQL
DECLARE ans RECORD; trans INT; BEGIN SELECT 1 INTO trans FROM biblio.record_entry b JOIN config.bib_source src ON (b.source = src.id) WHERE src.transcendant AND b.id = rid; FOR ans IN SELECT u.id, t.depth FROM actor.org_unit_ancestors(org) AS u JOIN actor.org_unit_type t ON (u.ou_type = t.id) LOOP RETURN QUERY WITH available_statuses AS (SELECT ARRAY_AGG(id) AS ids FROM config.copy_status WHERE is_available), cp AS( SELECT cp.id, (cp.status = ANY (available_statuses.ids))::INT as available, (cl.opac_visible AND cp.opac_visible)::INT as opac_visible FROM available_statuses, actor.org_unit_descendants(ans.id) d JOIN asset.copy cp ON (cp.circ_lib = d.id AND NOT cp.deleted) JOIN asset.copy_location cl ON (cp.location = cl.id AND NOT cl.deleted) JOIN asset.call_number cn ON (cn.record = rid AND cn.id = cp.call_number AND NOT cn.deleted) ), peer AS ( select cp.id, (cp.status = ANY (available_statuses.ids))::INT as available, (cl.opac_visible AND cp.opac_visible)::INT as opac_visible FROM available_statuses, actor.org_unit_descendants(ans.id) d JOIN asset.copy cp ON (cp.circ_lib = d.id AND NOT cp.deleted) JOIN asset.copy_location cl ON (cp.location = cl.id AND NOT cl.deleted) JOIN biblio.peer_bib_copy_map bp ON (bp.peer_record = rid AND bp.target_copy = cp.id) ) select ans.depth, ans.id, count(id), sum(x.available::int), sum(x.opac_visible::int), trans from ((select * from cp) union (select * from peer)) x group by 1,2,6; IF NOT FOUND THEN RETURN QUERY SELECT ans.depth, ans.id, 0::BIGINT, 0::BIGINT, 0::BIGINT, trans; END IF; END LOOP; RETURN; END;
Function: asset.stat_cat_check()
Returns: trigger
Language: PLPGSQL
DECLARE sipfield asset.stat_cat_sip_fields%ROWTYPE; use_count INT; BEGIN IF NEW.sip_field IS NOT NULL THEN SELECT INTO sipfield * FROM asset.stat_cat_sip_fields WHERE field = NEW.sip_field; IF sipfield.one_only THEN SELECT INTO use_count count(id) FROM asset.stat_cat WHERE sip_field = NEW.sip_field AND id != NEW.id; IF use_count > 0 THEN RAISE EXCEPTION 'Sip field cannot be used twice'; END IF; END IF; END IF; RETURN NEW; END;
Function: asset.status_default()
Returns: text
Language: SQL
SELECT '!(' || STRING_AGG(search.calculate_visibility_attribute(id, 'status')::TEXT,'|') || ')' FROM config.copy_status WHERE NOT opac_visible;
Function: asset.visible_orgs(otype text)
Returns: text
Language: SQL
SELECT '(' || STRING_AGG(search.calculate_visibility_attribute(id, $1)::TEXT,'|') || ')' FROM actor.org_unit WHERE opac_visible;
Schema auditor
Table: auditor.acq_fund_debit_history
F-Key | Name | Type | Description |
---|---|---|---|
audit_id | bigint | PRIMARY KEY | |
audit_time | timestamp with time zone | NOT NULL | |
audit_action | text | NOT NULL | |
audit_user | integer | ||
audit_ws | integer | ||
id | integer | NOT NULL | |
fund | integer | NOT NULL | |
origin_amount | numeric | NOT NULL | |
origin_currency_type | text | NOT NULL | |
amount | numeric | NOT NULL | |
encumbrance | boolean | NOT NULL | |
debit_type | text | NOT NULL | |
xfer_destination | integer | ||
create_time | timestamp with time zone | NOT NULL | |
invoice_entry | integer |
View: auditor.acq_fund_debit_lifecycle
F-Key | Name | Type | Description |
---|---|---|---|
audit_id | bigint | ||
audit_time | timestamp with time zone | ||
audit_action | text | ||
audit_user | integer | ||
audit_ws | integer | ||
id | integer | ||
fund | integer | ||
origin_amount | numeric | ||
origin_currency_type | text | ||
amount | numeric | ||
encumbrance | boolean | ||
debit_type | text | ||
xfer_destination | integer | ||
create_time | timestamp with time zone | ||
invoice_entry | integer |
SELECT'-1'::integer AS audit_id , now () AS audit_time , '-'::text AS audit_action , '-1'::integer AS audit_user , '-1'::integer AS audit_ws , fund_debit.id , fund_debit.fund , fund_debit.origin_amount , fund_debit.origin_currency_type , fund_debit.amount , fund_debit.encumbrance , fund_debit.debit_type , fund_debit.xfer_destination , fund_debit.create_time , fund_debit.invoice_entry FROM acq.fund_debit UNION ALL SELECT acq_fund_debit_history.audit_id , acq_fund_debit_history.audit_time , acq_fund_debit_history.audit_action , acq_fund_debit_history.audit_user , acq_fund_debit_history.audit_ws , acq_fund_debit_history.id , acq_fund_debit_history.fund , acq_fund_debit_history.origin_amount , acq_fund_debit_history.origin_currency_type , acq_fund_debit_history.amount , acq_fund_debit_history.encumbrance , acq_fund_debit_history.debit_type , acq_fund_debit_history.xfer_destination , acq_fund_debit_history.create_time , acq_fund_debit_history.invoice_entry FROM auditor.acq_fund_debit_history;
Table: auditor.acq_invoice_entry_history
F-Key | Name | Type | Description |
---|---|---|---|
audit_id | bigint | PRIMARY KEY | |
audit_time | timestamp with time zone | NOT NULL | |
audit_action | text | NOT NULL | |
audit_user | integer | ||
audit_ws | integer | ||
id | integer | NOT NULL | |
invoice | integer | NOT NULL | |
purchase_order | integer | ||
lineitem | integer | ||
inv_item_count | integer | NOT NULL | |
phys_item_count | integer | ||
note | text | ||
billed_per_item | boolean | ||
cost_billed | numeric(8,2) | ||
actual_cost | numeric(8,2) | ||
amount_paid | numeric(8,2) |
View: auditor.acq_invoice_entry_lifecycle
F-Key | Name | Type | Description |
---|---|---|---|
audit_id | bigint | ||
audit_time | timestamp with time zone | ||
audit_action | text | ||
audit_user | integer | ||
audit_ws | integer | ||
id | integer | ||
invoice | integer | ||
purchase_order | integer | ||
lineitem | integer | ||
inv_item_count | integer | ||
phys_item_count | integer | ||
note | text | ||
billed_per_item | boolean | ||
cost_billed | numeric(8,2) | ||
actual_cost | numeric(8,2) | ||
amount_paid | numeric(8,2) |
SELECT'-1'::integer AS audit_id , now () AS audit_time , '-'::text AS audit_action , '-1'::integer AS audit_user , '-1'::integer AS audit_ws , invoice_entry.id , invoice_entry.invoice , invoice_entry.purchase_order , invoice_entry.lineitem , invoice_entry.inv_item_count , invoice_entry.phys_item_count , invoice_entry.note , invoice_entry.billed_per_item , invoice_entry.cost_billed , invoice_entry.actual_cost , invoice_entry.amount_paid FROM acq.invoice_entry UNION ALL SELECT acq_invoice_entry_history.audit_id , acq_invoice_entry_history.audit_time , acq_invoice_entry_history.audit_action , acq_invoice_entry_history.audit_user , acq_invoice_entry_history.audit_ws , acq_invoice_entry_history.id , acq_invoice_entry_history.invoice , acq_invoice_entry_history.purchase_order , acq_invoice_entry_history.lineitem , acq_invoice_entry_history.inv_item_count , acq_invoice_entry_history.phys_item_count , acq_invoice_entry_history.note , acq_invoice_entry_history.billed_per_item , acq_invoice_entry_history.cost_billed , acq_invoice_entry_history.actual_cost , acq_invoice_entry_history.amount_paid FROM auditor.acq_invoice_entry_history;
Table: auditor.acq_invoice_history
F-Key | Name | Type | Description |
---|---|---|---|
audit_id | bigint | PRIMARY KEY | |
audit_time | timestamp with time zone | NOT NULL | |
audit_action | text | NOT NULL | |
audit_user | integer | ||
audit_ws | integer | ||
id | integer | NOT NULL | |
receiver | integer | NOT NULL | |
provider | integer | NOT NULL | |
shipper | integer | NOT NULL | |
recv_date | timestamp with time zone | NOT NULL | |
recv_method | text | NOT NULL | |
inv_type | text | ||
inv_ident | text | NOT NULL | |
payment_auth | text | ||
payment_method | text | ||
note | text | ||
close_date | timestamp with time zone | ||
closed_by | integer |
Table: auditor.acq_invoice_item_history
F-Key | Name | Type | Description |
---|---|---|---|
audit_id | bigint | PRIMARY KEY | |
audit_time | timestamp with time zone | NOT NULL | |
audit_action | text | NOT NULL | |
audit_user | integer | ||
audit_ws | integer | ||
id | integer | NOT NULL | |
invoice | integer | NOT NULL | |
purchase_order | integer | ||
fund_debit | integer | ||
inv_item_type | text | NOT NULL | |
title | text | ||
author | text | ||
note | text | ||
cost_billed | numeric(8,2) | ||
actual_cost | numeric(8,2) | ||
fund | integer | ||
amount_paid | numeric(8,2) | ||
po_item | integer | ||
target | bigint |
View: auditor.acq_invoice_item_lifecycle
F-Key | Name | Type | Description |
---|---|---|---|
audit_id | bigint | ||
audit_time | timestamp with time zone | ||
audit_action | text | ||
audit_user | integer | ||
audit_ws | integer | ||
id | integer | ||
invoice | integer | ||
purchase_order | integer | ||
fund_debit | integer | ||
inv_item_type | text | ||
title | text | ||
author | text | ||
note | text | ||
cost_billed | numeric(8,2) | ||
actual_cost | numeric(8,2) | ||
fund | integer | ||
amount_paid | numeric(8,2) | ||
po_item | integer | ||
target | bigint |
SELECT'-1'::integer AS audit_id , now () AS audit_time , '-'::text AS audit_action , '-1'::integer AS audit_user , '-1'::integer AS audit_ws , invoice_item.id , invoice_item.invoice , invoice_item.purchase_order , invoice_item.fund_debit , invoice_item.inv_item_type , invoice_item.title , invoice_item.author , invoice_item.note , invoice_item.cost_billed , invoice_item.actual_cost , invoice_item.fund , invoice_item.amount_paid , invoice_item.po_item , invoice_item.target FROM acq.invoice_item UNION ALL SELECT acq_invoice_item_history.audit_id , acq_invoice_item_history.audit_time , acq_invoice_item_history.audit_action , acq_invoice_item_history.audit_user , acq_invoice_item_history.audit_ws , acq_invoice_item_history.id , acq_invoice_item_history.invoice , acq_invoice_item_history.purchase_order , acq_invoice_item_history.fund_debit , acq_invoice_item_history.inv_item_type , acq_invoice_item_history.title , acq_invoice_item_history.author , acq_invoice_item_history.note , acq_invoice_item_history.cost_billed , acq_invoice_item_history.actual_cost , acq_invoice_item_history.fund , acq_invoice_item_history.amount_paid , acq_invoice_item_history.po_item , acq_invoice_item_history.target FROM auditor.acq_invoice_item_history;
View: auditor.acq_invoice_lifecycle
F-Key | Name | Type | Description |
---|---|---|---|
audit_id | bigint | ||
audit_time | timestamp with time zone | ||
audit_action | text | ||
audit_user | integer | ||
audit_ws | integer | ||
id | integer | ||
receiver | integer | ||
provider | integer | ||
shipper | integer | ||
recv_date | timestamp with time zone | ||
recv_method | text | ||
inv_type | text | ||
inv_ident | text | ||
payment_auth | text | ||
payment_method | text | ||
note | text | ||
close_date | timestamp with time zone | ||
closed_by | integer |
SELECT'-1'::integer AS audit_id , now () AS audit_time , '-'::text AS audit_action , '-1'::integer AS audit_user , '-1'::integer AS audit_ws , invoice.id , invoice.receiver , invoice.provider , invoice.shipper , invoice.recv_date , invoice.recv_method , invoice.inv_type , invoice.inv_ident , invoice.payment_auth , invoice.payment_method , invoice.note , invoice.close_date , invoice.closed_by FROM acq.invoice UNION ALL SELECT acq_invoice_history.audit_id , acq_invoice_history.audit_time , acq_invoice_history.audit_action , acq_invoice_history.audit_user , acq_invoice_history.audit_ws , acq_invoice_history.id , acq_invoice_history.receiver , acq_invoice_history.provider , acq_invoice_history.shipper , acq_invoice_history.recv_date , acq_invoice_history.recv_method , acq_invoice_history.inv_type , acq_invoice_history.inv_ident , acq_invoice_history.payment_auth , acq_invoice_history.payment_method , acq_invoice_history.note , acq_invoice_history.close_date , acq_invoice_history.closed_by FROM auditor.acq_invoice_history;
Table: auditor.actor_org_unit_history
F-Key | Name | Type | Description |
---|---|---|---|
audit_id | bigint | PRIMARY KEY | |
audit_time | timestamp with time zone | NOT NULL | |
audit_action | text | NOT NULL | |
audit_user | integer | ||
audit_ws | integer | ||
id | integer | NOT NULL | |
parent_ou | integer | ||
ou_type | integer | NOT NULL | |
ill_address | integer | ||
holds_address | integer | ||
mailing_address | integer | ||
billing_address | integer | ||
shortname | text | NOT NULL | |
name | text | NOT NULL | |
text | |||
phone | text | ||
opac_visible | boolean | NOT NULL | |
fiscal_calendar | integer | NOT NULL |
View: auditor.actor_org_unit_lifecycle
F-Key | Name | Type | Description |
---|---|---|---|
audit_id | bigint | ||
audit_time | timestamp with time zone | ||
audit_action | text | ||
audit_user | integer | ||
audit_ws | integer | ||
id | integer | ||
parent_ou | integer | ||
ou_type | integer | ||
ill_address | integer | ||
holds_address | integer | ||
mailing_address | integer | ||
billing_address | integer | ||
shortname | text | ||
name | text | ||
text | |||
phone | text | ||
opac_visible | boolean | ||
fiscal_calendar | integer |
SELECT'-1'::integer AS audit_id , now () AS audit_time , '-'::text AS audit_action , '-1'::integer AS audit_user , '-1'::integer AS audit_ws , org_unit.id , org_unit.parent_ou , org_unit.ou_type , org_unit.ill_address , org_unit.holds_address , org_unit.mailing_address , org_unit.billing_address , org_unit.shortname , org_unit.name , org_unit.email , org_unit.phone , org_unit.opac_visible , org_unit.fiscal_calendar FROM actor.org_unit UNION ALL SELECT actor_org_unit_history.audit_id , actor_org_unit_history.audit_time , actor_org_unit_history.audit_action , actor_org_unit_history.audit_user , actor_org_unit_history.audit_ws , actor_org_unit_history.id , actor_org_unit_history.parent_ou , actor_org_unit_history.ou_type , actor_org_unit_history.ill_address , actor_org_unit_history.holds_address , actor_org_unit_history.mailing_address , actor_org_unit_history.billing_address , actor_org_unit_history.shortname , actor_org_unit_history.name , actor_org_unit_history.email , actor_org_unit_history.phone , actor_org_unit_history.opac_visible , actor_org_unit_history.fiscal_calendar FROM auditor.actor_org_unit_history;
Table: auditor.actor_usr_address_history
F-Key | Name | Type | Description |
---|---|---|---|
audit_id | bigint | PRIMARY KEY | |
audit_time | timestamp with time zone | NOT NULL | |
audit_action | text | NOT NULL | |
audit_user | integer | ||
audit_ws | integer | ||
id | integer | NOT NULL | |
valid | boolean | NOT NULL | |
within_city_limits | boolean | NOT NULL | |
address_type | text | NOT NULL | |
usr | integer | NOT NULL | |
street1 | text | NOT NULL | |
street2 | text | ||
city | text | NOT NULL | |
county | text | ||
state | text | ||
country | text | NOT NULL | |
post_code | text | NOT NULL | |
pending | boolean | NOT NULL | |
replaces | integer |
View: auditor.actor_usr_address_lifecycle
F-Key | Name | Type | Description |
---|---|---|---|
audit_id | bigint | ||
audit_time | timestamp with time zone | ||
audit_action | text | ||
audit_user | integer | ||
audit_ws | integer | ||
id | integer | ||
valid | boolean | ||
within_city_limits | boolean | ||
address_type | text | ||
usr | integer | ||
street1 | text | ||
street2 | text | ||
city | text | ||
county | text | ||
state | text | ||
country | text | ||
post_code | text | ||
pending | boolean | ||
replaces | integer |
SELECT'-1'::integer AS audit_id , now () AS audit_time , '-'::text AS audit_action , '-1'::integer AS audit_user , '-1'::integer AS audit_ws , usr_address.id , usr_address.valid , usr_address.within_city_limits , usr_address.address_type , usr_address.usr , usr_address.street1 , usr_address.street2 , usr_address.city , usr_address.county , usr_address.state , usr_address.country , usr_address.post_code , usr_address.pending , usr_address.replaces FROM actor.usr_address UNION ALL SELECT actor_usr_address_history.audit_id , actor_usr_address_history.audit_time , actor_usr_address_history.audit_action , actor_usr_address_history.audit_user , actor_usr_address_history.audit_ws , actor_usr_address_history.id , actor_usr_address_history.valid , actor_usr_address_history.within_city_limits , actor_usr_address_history.address_type , actor_usr_address_history.usr , actor_usr_address_history.street1 , actor_usr_address_history.street2 , actor_usr_address_history.city , actor_usr_address_history.county , actor_usr_address_history.state , actor_usr_address_history.country , actor_usr_address_history.post_code , actor_usr_address_history.pending , actor_usr_address_history.replaces FROM auditor.actor_usr_address_history;
Table: auditor.actor_usr_history
F-Key | Name | Type | Description |
---|---|---|---|
audit_id | bigint | PRIMARY KEY | |
audit_time | timestamp with time zone | NOT NULL | |
audit_action | text | NOT NULL | |
audit_user | integer | ||
audit_ws | integer | ||
id | integer | NOT NULL | |
card | integer | ||
profile | integer | NOT NULL | |
usrname | text | NOT NULL | |
text | |||
passwd | text | NOT NULL | |
standing | integer | NOT NULL | |
ident_type | integer | NOT NULL | |
ident_value | text | ||
ident_type2 | integer | ||
ident_value2 | text | ||
net_access_level | integer | NOT NULL | |
photo_url | text | ||
prefix | text | ||
first_given_name | text | NOT NULL | |
second_given_name | text | ||
family_name | text | NOT NULL | |
suffix | text | ||
guardian | text | ||
pref_prefix | text | ||
pref_first_given_name | text | ||
pref_second_given_name | text | ||
pref_family_name | text | ||
pref_suffix | text | ||
name_keywords | text | ||
name_kw_tsvector | tsvector | ||
alias | text | ||
day_phone | text | ||
evening_phone | text | ||
other_phone | text | ||
mailing_address | integer | ||
billing_address | integer | ||
home_ou | integer | NOT NULL | |
dob | date | ||
active | boolean | NOT NULL | |
master_account | boolean | NOT NULL | |
super_user | boolean | NOT NULL | |
barred | boolean | NOT NULL | |
deleted | boolean | NOT NULL | |
juvenile | boolean | NOT NULL | |
usrgroup | integer | NOT NULL | |
claims_returned_count | integer | NOT NULL | |
credit_forward_balance | numeric(6,2) | NOT NULL | |
last_xact_id | text | NOT NULL | |
create_date | timestamp with time zone | NOT NULL | |
expire_date | timestamp with time zone | NOT NULL | |
claims_never_checked_out_count | integer | NOT NULL | |
last_update_time | timestamp with time zone | ||
locale | text |
View: auditor.actor_usr_lifecycle
F-Key | Name | Type | Description |
---|---|---|---|
audit_id | bigint | ||
audit_time | timestamp with time zone | ||
audit_action | text | ||
audit_user | integer | ||
audit_ws | integer | ||
id | integer | ||
card | integer | ||
profile | integer | ||
usrname | text | ||
text | |||
passwd | text | ||
standing | integer | ||
ident_type | integer | ||
ident_value | text | ||
ident_type2 | integer | ||
ident_value2 | text | ||
net_access_level | integer | ||
photo_url | text | ||
prefix | text | ||
first_given_name | text | ||
second_given_name | text | ||
family_name | text | ||
suffix | text | ||
guardian | text | ||
pref_prefix | text | ||
pref_first_given_name | text | ||
pref_second_given_name | text | ||
pref_family_name | text | ||
pref_suffix | text | ||
name_keywords | text | ||
name_kw_tsvector | tsvector | ||
alias | text | ||
day_phone | text | ||
evening_phone | text | ||
other_phone | text | ||
mailing_address | integer | ||
billing_address | integer | ||
home_ou | integer | ||
dob | date | ||
active | boolean | ||
master_account | boolean | ||
super_user | boolean | ||
barred | boolean | ||
deleted | boolean | ||
juvenile | boolean | ||
usrgroup | integer | ||
claims_returned_count | integer | ||
credit_forward_balance | numeric(6,2) | ||
last_xact_id | text | ||
create_date | timestamp with time zone | ||
expire_date | timestamp with time zone | ||
claims_never_checked_out_count | integer | ||
last_update_time | timestamp with time zone | ||
locale | text |
SELECT'-1'::integer AS audit_id , now () AS audit_time , '-'::text AS audit_action , '-1'::integer AS audit_user , '-1'::integer AS audit_ws , usr.id , usr.card , usr.profile , usr.usrname , usr.email , usr.passwd , usr.standing , usr.ident_type , usr.ident_value , usr.ident_type2 , usr.ident_value2 , usr.net_access_level , usr.photo_url , usr.prefix , usr.first_given_name , usr.second_given_name , usr.family_name , usr.suffix , usr.guardian , usr.pref_prefix , usr.pref_first_given_name , usr.pref_second_given_name , usr.pref_family_name , usr.pref_suffix , usr.name_keywords , usr.name_kw_tsvector , usr.alias , usr.day_phone , usr.evening_phone , usr.other_phone , usr.mailing_address , usr.billing_address , usr.home_ou , usr.dob , usr.active , usr.master_account , usr.super_user , usr.barred , usr.deleted , usr.juvenile , usr.usrgroup , usr.claims_returned_count , usr.credit_forward_balance , usr.last_xact_id , usr.create_date , usr.expire_date , usr.claims_never_checked_out_count , usr.last_update_time , usr.locale FROM actor.usr UNION ALL SELECT actor_usr_history.audit_id , actor_usr_history.audit_time , actor_usr_history.audit_action , actor_usr_history.audit_user , actor_usr_history.audit_ws , actor_usr_history.id , actor_usr_history.card , actor_usr_history.profile , actor_usr_history.usrname , actor_usr_history.email , actor_usr_history.passwd , actor_usr_history.standing , actor_usr_history.ident_type , actor_usr_history.ident_value , actor_usr_history.ident_type2 , actor_usr_history.ident_value2 , actor_usr_history.net_access_level , actor_usr_history.photo_url , actor_usr_history.prefix , actor_usr_history.first_given_name , actor_usr_history.second_given_name , actor_usr_history.family_name , actor_usr_history.suffix , actor_usr_history.guardian , actor_usr_history.pref_prefix , actor_usr_history.pref_first_given_name , actor_usr_history.pref_second_given_name , actor_usr_history.pref_family_name , actor_usr_history.pref_suffix , actor_usr_history.name_keywords , actor_usr_history.name_kw_tsvector , actor_usr_history.alias , actor_usr_history.day_phone , actor_usr_history.evening_phone , actor_usr_history.other_phone , actor_usr_history.mailing_address , actor_usr_history.billing_address , actor_usr_history.home_ou , actor_usr_history.dob , actor_usr_history.active , actor_usr_history.master_account , actor_usr_history.super_user , actor_usr_history.barred , actor_usr_history.deleted , actor_usr_history.juvenile , actor_usr_history.usrgroup , actor_usr_history.claims_returned_count , actor_usr_history.credit_forward_balance , actor_usr_history.last_xact_id , actor_usr_history.create_date , actor_usr_history.expire_date , actor_usr_history.claims_never_checked_out_count , actor_usr_history.last_update_time , actor_usr_history.locale FROM auditor.actor_usr_history;
Table: auditor.asset_call_number_history
F-Key | Name | Type | Description |
---|---|---|---|
audit_id | bigint | PRIMARY KEY | |
audit_time | timestamp with time zone | NOT NULL | |
audit_action | text | NOT NULL | |
audit_user | integer | ||
audit_ws | integer | ||
id | bigint | NOT NULL | |
creator | bigint | NOT NULL | |
create_date | timestamp with time zone | ||
editor | bigint | NOT NULL | |
edit_date | timestamp with time zone | ||
record | bigint | NOT NULL | |
owning_lib | integer | NOT NULL | |
label | text | NOT NULL | |
deleted | boolean | NOT NULL | |
prefix | integer | NOT NULL | |
suffix | integer | NOT NULL | |
label_class | bigint | NOT NULL | |
label_sortkey | text |
View: auditor.asset_call_number_lifecycle
F-Key | Name | Type | Description |
---|---|---|---|
audit_id | bigint | ||
audit_time | timestamp with time zone | ||
audit_action | text | ||
audit_user | integer | ||
audit_ws | integer | ||
id | bigint | ||
creator | bigint | ||
create_date | timestamp with time zone | ||
editor | bigint | ||
edit_date | timestamp with time zone | ||
record | bigint | ||
owning_lib | integer | ||
label | text | ||
deleted | boolean | ||
prefix | integer | ||
suffix | integer | ||
label_class | bigint | ||
label_sortkey | text |
SELECT'-1'::integer AS audit_id , now () AS audit_time , '-'::text AS audit_action , '-1'::integer AS audit_user , '-1'::integer AS audit_ws , call_number.id , call_number.creator , call_number.create_date , call_number.editor , call_number.edit_date , call_number.record , call_number.owning_lib , call_number.label , call_number.deleted , call_number.prefix , call_number.suffix , call_number.label_class , call_number.label_sortkey FROM asset.call_number UNION ALL SELECT asset_call_number_history.audit_id , asset_call_number_history.audit_time , asset_call_number_history.audit_action , asset_call_number_history.audit_user , asset_call_number_history.audit_ws , asset_call_number_history.id , asset_call_number_history.creator , asset_call_number_history.create_date , asset_call_number_history.editor , asset_call_number_history.edit_date , asset_call_number_history.record , asset_call_number_history.owning_lib , asset_call_number_history.label , asset_call_number_history.deleted , asset_call_number_history.prefix , asset_call_number_history.suffix , asset_call_number_history.label_class , asset_call_number_history.label_sortkey FROM auditor.asset_call_number_history;
Table: auditor.asset_copy_history
F-Key | Name | Type | Description |
---|---|---|---|
audit_id | bigint | PRIMARY KEY | |
audit_time | timestamp with time zone | NOT NULL | |
audit_action | text | NOT NULL | |
audit_user | integer | ||
audit_ws | integer | ||
id | bigint | NOT NULL | |
circ_lib | integer | NOT NULL | |
creator | bigint | NOT NULL | |
call_number | bigint | NOT NULL | |
editor | bigint | NOT NULL | |
create_date | timestamp with time zone | ||
edit_date | timestamp with time zone | ||
copy_number | integer | ||
status | integer | NOT NULL | |
location | integer | NOT NULL | |
loan_duration | integer | NOT NULL | |
fine_level | integer | NOT NULL | |
age_protect | integer | ||
circulate | boolean | NOT NULL | |
deposit | boolean | NOT NULL | |
ref | boolean | NOT NULL | |
holdable | boolean | NOT NULL | |
deposit_amount | numeric(6,2) | NOT NULL | |
price | numeric(8,2) | ||
barcode | text | NOT NULL | |
circ_modifier | text | ||
circ_as_type | text | ||
dummy_title | text | ||
dummy_author | text | ||
alert_message | text | ||
opac_visible | boolean | NOT NULL | |
deleted | boolean | NOT NULL | |
floating | integer | ||
dummy_isbn | text | ||
status_changed_time | timestamp with time zone | ||
active_date | timestamp with time zone | ||
mint_condition | boolean | NOT NULL | |
cost | numeric(8,2) |
View: auditor.asset_copy_lifecycle
F-Key | Name | Type | Description |
---|---|---|---|
audit_id | bigint | ||
audit_time | timestamp with time zone | ||
audit_action | text | ||
audit_user | integer | ||
audit_ws | integer | ||
id | bigint | ||
circ_lib | integer | ||
creator | bigint | ||
call_number | bigint | ||
editor | bigint | ||
create_date | timestamp with time zone | ||
edit_date | timestamp with time zone | ||
copy_number | integer | ||
status | integer | ||
location | integer | ||
loan_duration | integer | ||
fine_level | integer | ||
age_protect | integer | ||
circulate | boolean | ||
deposit | boolean | ||
ref | boolean | ||
holdable | boolean | ||
deposit_amount | numeric(6,2) | ||
price | numeric(8,2) | ||
barcode | text | ||
circ_modifier | text | ||
circ_as_type | text | ||
dummy_title | text | ||
dummy_author | text | ||
alert_message | text | ||
opac_visible | boolean | ||
deleted | boolean | ||
floating | integer | ||
dummy_isbn | text | ||
status_changed_time | timestamp with time zone | ||
active_date | timestamp with time zone | ||
mint_condition | boolean | ||
cost | numeric(8,2) |
SELECT'-1'::integer AS audit_id , now () AS audit_time , '-'::text AS audit_action , '-1'::integer AS audit_user , '-1'::integer AS audit_ws , copy.id , copy.circ_lib , copy.creator , copy.call_number , copy.editor , copy.create_date , copy.edit_date , copy.copy_number , copy.status , copy.location , copy.loan_duration , copy.fine_level , copy.age_protect , copy.circulate , copy.deposit , copy.ref , copy.holdable , copy.deposit_amount , copy.price , copy.barcode , copy.circ_modifier , copy.circ_as_type , copy.dummy_title , copy.dummy_author , copy.alert_message , copy.opac_visible , copy.deleted , copy.floating , copy.dummy_isbn , copy.status_changed_time , copy.active_date , copy.mint_condition , copy.cost FROM asset.copy UNION ALL SELECT asset_copy_history.audit_id , asset_copy_history.audit_time , asset_copy_history.audit_action , asset_copy_history.audit_user , asset_copy_history.audit_ws , asset_copy_history.id , asset_copy_history.circ_lib , asset_copy_history.creator , asset_copy_history.call_number , asset_copy_history.editor , asset_copy_history.create_date , asset_copy_history.edit_date , asset_copy_history.copy_number , asset_copy_history.status , asset_copy_history.location , asset_copy_history.loan_duration , asset_copy_history.fine_level , asset_copy_history.age_protect , asset_copy_history.circulate , asset_copy_history.deposit , asset_copy_history.ref , asset_copy_history.holdable , asset_copy_history.deposit_amount , asset_copy_history.price , asset_copy_history.barcode , asset_copy_history.circ_modifier , asset_copy_history.circ_as_type , asset_copy_history.dummy_title , asset_copy_history.dummy_author , asset_copy_history.alert_message , asset_copy_history.opac_visible , asset_copy_history.deleted , asset_copy_history.floating , asset_copy_history.dummy_isbn , asset_copy_history.status_changed_time , asset_copy_history.active_date , asset_copy_history.mint_condition , asset_copy_history.cost FROM auditor.asset_copy_history;
Table: auditor.biblio_record_entry_history
F-Key | Name | Type | Description |
---|---|---|---|
audit_id | bigint | PRIMARY KEY | |
audit_time | timestamp with time zone | NOT NULL | |
audit_action | text | NOT NULL | |
audit_user | integer | ||
audit_ws | integer | ||
id | bigint | NOT NULL | |
creator | integer | NOT NULL | |
editor | integer | NOT NULL | |
source | integer | ||
quality | integer | ||
create_date | timestamp with time zone | NOT NULL | |
edit_date | timestamp with time zone | NOT NULL | |
active | boolean | NOT NULL | |
deleted | boolean | NOT NULL | |
fingerprint | text | ||
tcn_source | text | NOT NULL | |
tcn_value | text | NOT NULL | |
marc | text | NOT NULL | |
last_xact_id | text | NOT NULL | |
vis_attr_vector | integer[] | ||
owner | integer | ||
share_depth | integer | ||
merge_date | timestamp with time zone | ||
merged_to | bigint |
View: auditor.biblio_record_entry_lifecycle
F-Key | Name | Type | Description |
---|---|---|---|
audit_id | bigint | ||
audit_time | timestamp with time zone | ||
audit_action | text | ||
audit_user | integer | ||
audit_ws | integer | ||
id | bigint | ||
creator | integer | ||
editor | integer | ||
source | integer | ||
quality | integer | ||
create_date | timestamp with time zone | ||
edit_date | timestamp with time zone | ||
active | boolean | ||
deleted | boolean | ||
fingerprint | text | ||
tcn_source | text | ||
tcn_value | text | ||
marc | text | ||
last_xact_id | text | ||
vis_attr_vector | integer[] | ||
owner | integer | ||
share_depth | integer | ||
merge_date | timestamp with time zone | ||
merged_to | bigint |
SELECT'-1'::integer AS audit_id , now () AS audit_time , '-'::text AS audit_action , '-1'::integer AS audit_user , '-1'::integer AS audit_ws , record_entry.id , record_entry.creator , record_entry.editor , record_entry.source , record_entry.quality , record_entry.create_date , record_entry.edit_date , record_entry.active , record_entry.deleted , record_entry.fingerprint , record_entry.tcn_source , record_entry.tcn_value , record_entry.marc , record_entry.last_xact_id , record_entry.vis_attr_vector , record_entry.owner , record_entry.share_depth , record_entry.merge_date , record_entry.merged_to FROM biblio.record_entry UNION ALL SELECT biblio_record_entry_history.audit_id , biblio_record_entry_history.audit_time , biblio_record_entry_history.audit_action , biblio_record_entry_history.audit_user , biblio_record_entry_history.audit_ws , biblio_record_entry_history.id , biblio_record_entry_history.creator , biblio_record_entry_history.editor , biblio_record_entry_history.source , biblio_record_entry_history.quality , biblio_record_entry_history.create_date , biblio_record_entry_history.edit_date , biblio_record_entry_history.active , biblio_record_entry_history.deleted , biblio_record_entry_history.fingerprint , biblio_record_entry_history.tcn_source , biblio_record_entry_history.tcn_value , biblio_record_entry_history.marc , biblio_record_entry_history.last_xact_id , biblio_record_entry_history.vis_attr_vector , biblio_record_entry_history.owner , biblio_record_entry_history.share_depth , biblio_record_entry_history.merge_date , biblio_record_entry_history.merged_to FROM auditor.biblio_record_entry_history;
Table: auditor.serial_unit_history
F-Key | Name | Type | Description |
---|---|---|---|
audit_id | bigint | PRIMARY KEY | |
audit_time | timestamp with time zone | NOT NULL | |
audit_action | text | NOT NULL | |
audit_user | integer | ||
audit_ws | integer | ||
id | bigint | NOT NULL | |
circ_lib | integer | NOT NULL | |
creator | bigint | NOT NULL | |
call_number | bigint | NOT NULL | |
editor | bigint | NOT NULL | |
create_date | timestamp with time zone | ||
edit_date | timestamp with time zone | ||
copy_number | integer | ||
status | integer | NOT NULL | |
location | integer | NOT NULL | |
loan_duration | integer | NOT NULL | |
fine_level | integer | NOT NULL | |
age_protect | integer | ||
circulate | boolean | NOT NULL | |
deposit | boolean | NOT NULL | |
ref | boolean | NOT NULL | |
holdable | boolean | NOT NULL | |
deposit_amount | numeric(6,2) | NOT NULL | |
price | numeric(8,2) | ||
barcode | text | NOT NULL | |
circ_modifier | text | ||
circ_as_type | text | ||
dummy_title | text | ||
dummy_author | text | ||
alert_message | text | ||
opac_visible | boolean | NOT NULL | |
deleted | boolean | NOT NULL | |
floating | integer | ||
dummy_isbn | text | ||
status_changed_time | timestamp with time zone | ||
active_date | timestamp with time zone | ||
mint_condition | boolean | NOT NULL | |
cost | numeric(8,2) | ||
sort_key | text | ||
detailed_contents | text | NOT NULL | |
summary_contents | text | NOT NULL |
View: auditor.serial_unit_lifecycle
F-Key | Name | Type | Description |
---|---|---|---|
audit_id | bigint | ||
audit_time | timestamp with time zone | ||
audit_action | text | ||
audit_user | integer | ||
audit_ws | integer | ||
id | bigint | ||
circ_lib | integer | ||
creator | bigint | ||
call_number | bigint | ||
editor | bigint | ||
create_date | timestamp with time zone | ||
edit_date | timestamp with time zone | ||
copy_number | integer | ||
status | integer | ||
location | integer | ||
loan_duration | integer | ||
fine_level | integer | ||
age_protect | integer | ||
circulate | boolean | ||
deposit | boolean | ||
ref | boolean | ||
holdable | boolean | ||
deposit_amount | numeric(6,2) | ||
price | numeric(8,2) | ||
barcode | text | ||
circ_modifier | text | ||
circ_as_type | text | ||
dummy_title | text | ||
dummy_author | text | ||
alert_message | text | ||
opac_visible | boolean | ||
deleted | boolean | ||
floating | integer | ||
dummy_isbn | text | ||
status_changed_time | timestamp with time zone | ||
active_date | timestamp with time zone | ||
mint_condition | boolean | ||
cost | numeric(8,2) | ||
sort_key | text | ||
detailed_contents | text | ||
summary_contents | text |
SELECT'-1'::integer AS audit_id , now () AS audit_time , '-'::text AS audit_action , '-1'::integer AS audit_user , '-1'::integer AS audit_ws , unit.id , unit.circ_lib , unit.creator , unit.call_number , unit.editor , unit.create_date , unit.edit_date , unit.copy_number , unit.status , unit.location , unit.loan_duration , unit.fine_level , unit.age_protect , unit.circulate , unit.deposit , unit.ref , unit.holdable , unit.deposit_amount , unit.price , unit.barcode , unit.circ_modifier , unit.circ_as_type , unit.dummy_title , unit.dummy_author , unit.alert_message , unit.opac_visible , unit.deleted , unit.floating , unit.dummy_isbn , unit.status_changed_time , unit.active_date , unit.mint_condition , unit.cost , unit.sort_key , unit.detailed_contents , unit.summary_contents FROM serial.unit UNION ALL SELECT serial_unit_history.audit_id , serial_unit_history.audit_time , serial_unit_history.audit_action , serial_unit_history.audit_user , serial_unit_history.audit_ws , serial_unit_history.id , serial_unit_history.circ_lib , serial_unit_history.creator , serial_unit_history.call_number , serial_unit_history.editor , serial_unit_history.create_date , serial_unit_history.edit_date , serial_unit_history.copy_number , serial_unit_history.status , serial_unit_history.location , serial_unit_history.loan_duration , serial_unit_history.fine_level , serial_unit_history.age_protect , serial_unit_history.circulate , serial_unit_history.deposit , serial_unit_history.ref , serial_unit_history.holdable , serial_unit_history.deposit_amount , serial_unit_history.price , serial_unit_history.barcode , serial_unit_history.circ_modifier , serial_unit_history.circ_as_type , serial_unit_history.dummy_title , serial_unit_history.dummy_author , serial_unit_history.alert_message , serial_unit_history.opac_visible , serial_unit_history.deleted , serial_unit_history.floating , serial_unit_history.dummy_isbn , serial_unit_history.status_changed_time , serial_unit_history.active_date , serial_unit_history.mint_condition , serial_unit_history.cost , serial_unit_history.sort_key , serial_unit_history.detailed_contents , serial_unit_history.summary_contents FROM auditor.serial_unit_history;
Function: auditor.audit_acq_fund_debit_func()
Returns: trigger
Language: PLPGSQL
BEGIN INSERT INTO auditor.acq_fund_debit_history ( audit_id, audit_time, audit_action, audit_user, audit_ws, id, fund, origin_amount, origin_currency_type, amount, encumbrance, debit_type, xfer_destination, create_time, invoice_entry ) SELECT nextval('auditor.acq_fund_debit_pkey_seq'), now(), SUBSTR(TG_OP,1,1), eg_user, eg_ws, OLD.id, OLD.fund, OLD.origin_amount, OLD.origin_currency_type, OLD.amount, OLD.encumbrance, OLD.debit_type, OLD.xfer_destination, OLD.create_time, OLD.invoice_entry FROM auditor.get_audit_info(); RETURN NULL; END;
Function: auditor.audit_acq_invoice_entry_func()
Returns: trigger
Language: PLPGSQL
BEGIN INSERT INTO auditor.acq_invoice_entry_history ( audit_id, audit_time, audit_action, audit_user, audit_ws, id, invoice, purchase_order, lineitem, inv_item_count, phys_item_count, note, billed_per_item, cost_billed, actual_cost, amount_paid ) SELECT nextval('auditor.acq_invoice_entry_pkey_seq'), now(), SUBSTR(TG_OP,1,1), eg_user, eg_ws, OLD.id, OLD.invoice, OLD.purchase_order, OLD.lineitem, OLD.inv_item_count, OLD.phys_item_count, OLD.note, OLD.billed_per_item, OLD.cost_billed, OLD.actual_cost, OLD.amount_paid FROM auditor.get_audit_info(); RETURN NULL; END;
Function: auditor.audit_acq_invoice_func()
Returns: trigger
Language: PLPGSQL
BEGIN INSERT INTO auditor.acq_invoice_history ( audit_id, audit_time, audit_action, audit_user, audit_ws, id, receiver, provider, shipper, recv_date, recv_method, inv_type, inv_ident, payment_auth, payment_method, note, close_date, closed_by ) SELECT nextval('auditor.acq_invoice_pkey_seq'), now(), SUBSTR(TG_OP,1,1), eg_user, eg_ws, OLD.id, OLD.receiver, OLD.provider, OLD.shipper, OLD.recv_date, OLD.recv_method, OLD.inv_type, OLD.inv_ident, OLD.payment_auth, OLD.payment_method, OLD.note, OLD.close_date, OLD.closed_by FROM auditor.get_audit_info(); RETURN NULL; END;
Function: auditor.audit_acq_invoice_item_func()
Returns: trigger
Language: PLPGSQL
BEGIN INSERT INTO auditor.acq_invoice_item_history ( audit_id, audit_time, audit_action, audit_user, audit_ws, id, invoice, purchase_order, fund_debit, inv_item_type, title, author, note, cost_billed, actual_cost, fund, amount_paid, po_item, target ) SELECT nextval('auditor.acq_invoice_item_pkey_seq'), now(), SUBSTR(TG_OP,1,1), eg_user, eg_ws, OLD.id, OLD.invoice, OLD.purchase_order, OLD.fund_debit, OLD.inv_item_type, OLD.title, OLD.author, OLD.note, OLD.cost_billed, OLD.actual_cost, OLD.fund, OLD.amount_paid, OLD.po_item, OLD.target FROM auditor.get_audit_info(); RETURN NULL; END;
Function: auditor.audit_actor_org_unit_func()
Returns: trigger
Language: PLPGSQL
BEGIN INSERT INTO auditor.actor_org_unit_history ( audit_id, audit_time, audit_action, audit_user, audit_ws, id, parent_ou, ou_type, ill_address, holds_address, mailing_address, billing_address, shortname, name, email, phone, opac_visible, fiscal_calendar ) SELECT nextval('auditor.actor_org_unit_pkey_seq'), now(), SUBSTR(TG_OP,1,1), eg_user, eg_ws, OLD.id, OLD.parent_ou, OLD.ou_type, OLD.ill_address, OLD.holds_address, OLD.mailing_address, OLD.billing_address, OLD.shortname, OLD.name, OLD.email, OLD.phone, OLD.opac_visible, OLD.fiscal_calendar FROM auditor.get_audit_info(); RETURN NULL; END;
Function: auditor.audit_actor_usr_address_func()
Returns: trigger
Language: PLPGSQL
BEGIN INSERT INTO auditor.actor_usr_address_history ( audit_id, audit_time, audit_action, audit_user, audit_ws, id, valid, within_city_limits, address_type, usr, street1, street2, city, county, state, country, post_code, pending, replaces ) SELECT nextval('auditor.actor_usr_address_pkey_seq'), now(), SUBSTR(TG_OP,1,1), eg_user, eg_ws, OLD.id, OLD.valid, OLD.within_city_limits, OLD.address_type, OLD.usr, OLD.street1, OLD.street2, OLD.city, OLD.county, OLD.state, OLD.country, OLD.post_code, OLD.pending, OLD.replaces FROM auditor.get_audit_info(); RETURN NULL; END;
Function: auditor.audit_actor_usr_func()
Returns: trigger
Language: PLPGSQL
BEGIN INSERT INTO auditor.actor_usr_history ( audit_id, audit_time, audit_action, audit_user, audit_ws, id, card, profile, usrname, email, passwd, standing, ident_type, ident_value, ident_type2, ident_value2, net_access_level, photo_url, prefix, first_given_name, second_given_name, family_name, suffix, guardian, pref_prefix, pref_first_given_name, pref_second_given_name, pref_family_name, pref_suffix, name_keywords, name_kw_tsvector, alias, day_phone, evening_phone, other_phone, mailing_address, billing_address, home_ou, dob, active, master_account, super_user, barred, deleted, juvenile, usrgroup, claims_returned_count, credit_forward_balance, last_xact_id, create_date, expire_date, claims_never_checked_out_count, last_update_time, locale ) SELECT nextval('auditor.actor_usr_pkey_seq'), now(), SUBSTR(TG_OP,1,1), eg_user, eg_ws, OLD.id, OLD.card, OLD.profile, OLD.usrname, OLD.email, OLD.passwd, OLD.standing, OLD.ident_type, OLD.ident_value, OLD.ident_type2, OLD.ident_value2, OLD.net_access_level, OLD.photo_url, OLD.prefix, OLD.first_given_name, OLD.second_given_name, OLD.family_name, OLD.suffix, OLD.guardian, OLD.pref_prefix, OLD.pref_first_given_name, OLD.pref_second_given_name, OLD.pref_family_name, OLD.pref_suffix, OLD.name_keywords, OLD.name_kw_tsvector, OLD.alias, OLD.day_phone, OLD.evening_phone, OLD.other_phone, OLD.mailing_address, OLD.billing_address, OLD.home_ou, OLD.dob, OLD.active, OLD.master_account, OLD.super_user, OLD.barred, OLD.deleted, OLD.juvenile, OLD.usrgroup, OLD.claims_returned_count, OLD.credit_forward_balance, OLD.last_xact_id, OLD.create_date, OLD.expire_date, OLD.claims_never_checked_out_count, OLD.last_update_time, OLD.locale FROM auditor.get_audit_info(); RETURN NULL; END;
Function: auditor.audit_asset_call_number_func()
Returns: trigger
Language: PLPGSQL
BEGIN INSERT INTO auditor.asset_call_number_history ( audit_id, audit_time, audit_action, audit_user, audit_ws, id, creator, create_date, editor, edit_date, record, owning_lib, label, deleted, prefix, suffix, label_class, label_sortkey ) SELECT nextval('auditor.asset_call_number_pkey_seq'), now(), SUBSTR(TG_OP,1,1), eg_user, eg_ws, OLD.id, OLD.creator, OLD.create_date, OLD.editor, OLD.edit_date, OLD.record, OLD.owning_lib, OLD.label, OLD.deleted, OLD.prefix, OLD.suffix, OLD.label_class, OLD.label_sortkey FROM auditor.get_audit_info(); RETURN NULL; END;
Function: auditor.audit_asset_copy_func()
Returns: trigger
Language: PLPGSQL
BEGIN INSERT INTO auditor.asset_copy_history ( audit_id, audit_time, audit_action, audit_user, audit_ws, id, circ_lib, creator, call_number, editor, create_date, edit_date, copy_number, status, location, loan_duration, fine_level, age_protect, circulate, deposit, ref, holdable, deposit_amount, price, barcode, circ_modifier, circ_as_type, dummy_title, dummy_author, alert_message, opac_visible, deleted, floating, dummy_isbn, status_changed_time, active_date, mint_condition, cost ) SELECT nextval('auditor.asset_copy_pkey_seq'), now(), SUBSTR(TG_OP,1,1), eg_user, eg_ws, OLD.id, OLD.circ_lib, OLD.creator, OLD.call_number, OLD.editor, OLD.create_date, OLD.edit_date, OLD.copy_number, OLD.status, OLD.location, OLD.loan_duration, OLD.fine_level, OLD.age_protect, OLD.circulate, OLD.deposit, OLD.ref, OLD.holdable, OLD.deposit_amount, OLD.price, OLD.barcode, OLD.circ_modifier, OLD.circ_as_type, OLD.dummy_title, OLD.dummy_author, OLD.alert_message, OLD.opac_visible, OLD.deleted, OLD.floating, OLD.dummy_isbn, OLD.status_changed_time, OLD.active_date, OLD.mint_condition, OLD.cost FROM auditor.get_audit_info(); RETURN NULL; END;
Function: auditor.audit_biblio_record_entry_func()
Returns: trigger
Language: PLPGSQL
BEGIN INSERT INTO auditor.biblio_record_entry_history ( audit_id, audit_time, audit_action, audit_user, audit_ws, id, creator, editor, source, quality, create_date, edit_date, active, deleted, fingerprint, tcn_source, tcn_value, marc, last_xact_id, vis_attr_vector, owner, share_depth, merge_date, merged_to ) SELECT nextval('auditor.biblio_record_entry_pkey_seq'), now(), SUBSTR(TG_OP,1,1), eg_user, eg_ws, OLD.id, OLD.creator, OLD.editor, OLD.source, OLD.quality, OLD.create_date, OLD.edit_date, OLD.active, OLD.deleted, OLD.fingerprint, OLD.tcn_source, OLD.tcn_value, OLD.marc, OLD.last_xact_id, OLD.vis_attr_vector, OLD.owner, OLD.share_depth, OLD.merge_date, OLD.merged_to FROM auditor.get_audit_info(); RETURN NULL; END;
Function: auditor.audit_serial_unit_func()
Returns: trigger
Language: PLPGSQL
BEGIN INSERT INTO auditor.serial_unit_history ( audit_id, audit_time, audit_action, audit_user, audit_ws, id, circ_lib, creator, call_number, editor, create_date, edit_date, copy_number, status, location, loan_duration, fine_level, age_protect, circulate, deposit, ref, holdable, deposit_amount, price, barcode, circ_modifier, circ_as_type, dummy_title, dummy_author, alert_message, opac_visible, deleted, floating, dummy_isbn, status_changed_time, active_date, mint_condition, cost, sort_key, detailed_contents, summary_contents ) SELECT nextval('auditor.serial_unit_pkey_seq'), now(), SUBSTR(TG_OP,1,1), eg_user, eg_ws, OLD.id, OLD.circ_lib, OLD.creator, OLD.call_number, OLD.editor, OLD.create_date, OLD.edit_date, OLD.copy_number, OLD.status, OLD.location, OLD.loan_duration, OLD.fine_level, OLD.age_protect, OLD.circulate, OLD.deposit, OLD.ref, OLD.holdable, OLD.deposit_amount, OLD.price, OLD.barcode, OLD.circ_modifier, OLD.circ_as_type, OLD.dummy_title, OLD.dummy_author, OLD.alert_message, OLD.opac_visible, OLD.deleted, OLD.floating, OLD.dummy_isbn, OLD.status_changed_time, OLD.active_date, OLD.mint_condition, OLD.cost, OLD.sort_key, OLD.detailed_contents, OLD.summary_contents FROM auditor.get_audit_info(); RETURN NULL; END;
Function: auditor.clear_audit_info()
Returns: void
Language: PLPERLU
delete($_SHARED{"eg_audit_user"}); delete($_SHARED{"eg_audit_ws"});
Function: auditor.create_auditor(tbl text, sch text)
Returns: boolean
Language: PLPGSQL
BEGIN PERFORM auditor.create_auditor_seq(sch, tbl); PERFORM auditor.create_auditor_history(sch, tbl); PERFORM auditor.create_auditor_func(sch, tbl); PERFORM auditor.create_auditor_update_trigger(sch, tbl); PERFORM auditor.create_auditor_lifecycle(sch, tbl); RETURN TRUE; END;
Function: auditor.create_auditor_func(tbl text, sch text)
Returns: boolean
Language: PLPGSQL
DECLARE column_list TEXT[]; BEGIN SELECT INTO column_list array_agg(a.attname) FROM pg_catalog.pg_attribute a JOIN pg_catalog.pg_class c ON a.attrelid = c.oid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE relkind = 'r' AND n.nspname = sch AND c.relname = tbl AND a.attnum > 0 AND NOT a.attisdropped; EXECUTE $$ CREATE OR REPLACE FUNCTION auditor.audit_$$ || sch || $$_$$ || tbl || $$_func () RETURNS TRIGGER AS $func$ BEGIN INSERT INTO auditor.$$ || sch || $$_$$ || tbl || $$_history ( audit_id, audit_time, audit_action, audit_user, audit_ws, $$ || array_to_string(column_list, ', ') || $$ ) SELECT nextval('auditor.$$ || sch || $$_$$ || tbl || $$_pkey_seq'), now(), SUBSTR(TG_OP,1,1), eg_user, eg_ws, OLD.$$ || array_to_string(column_list, ', OLD.') || $$ FROM auditor.get_audit_info(); RETURN NULL; END; $func$ LANGUAGE 'plpgsql'; $$; RETURN TRUE; END;
Function: auditor.create_auditor_history(tbl text, sch text)
Returns: boolean
Language: PLPGSQL
BEGIN EXECUTE $$ CREATE TABLE auditor.$$ || sch || $$_$$ || tbl || $$_history ( audit_id BIGINT PRIMARY KEY, audit_time TIMESTAMP WITH TIME ZONE NOT NULL, audit_action TEXT NOT NULL, audit_user INT, audit_ws INT, LIKE $$ || sch || $$.$$ || tbl || $$ ); $$; RETURN TRUE; END;
Function: auditor.create_auditor_lifecycle(tbl text, sch text)
Returns: boolean
Language: PLPGSQL
DECLARE column_list TEXT[]; BEGIN SELECT INTO column_list array_agg(a.attname) FROM pg_catalog.pg_attribute a JOIN pg_catalog.pg_class c ON a.attrelid = c.oid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE relkind = 'r' AND n.nspname = sch AND c.relname = tbl AND a.attnum > 0 AND NOT a.attisdropped; EXECUTE $$ CREATE VIEW auditor.$$ || sch || $$_$$ || tbl || $$_lifecycle AS SELECT -1 AS audit_id, now() AS audit_time, '-' AS audit_action, -1 AS audit_user, -1 AS audit_ws, $$ || array_to_string(column_list, ', ') || $$ FROM $$ || sch || $$.$$ || tbl || $$ UNION ALL SELECT audit_id, audit_time, audit_action, audit_user, audit_ws, $$ || array_to_string(column_list, ', ') || $$ FROM auditor.$$ || sch || $$_$$ || tbl || $$_history; $$; RETURN TRUE; END;
Function: auditor.create_auditor_seq(tbl text, sch text)
Returns: boolean
Language: PLPGSQL
BEGIN EXECUTE $$ CREATE SEQUENCE auditor.$$ || sch || $$_$$ || tbl || $$_pkey_seq; $$; RETURN TRUE; END;
Function: auditor.create_auditor_update_trigger(tbl text, sch text)
Returns: boolean
Language: PLPGSQL
BEGIN EXECUTE $$ CREATE TRIGGER audit_$$ || sch || $$_$$ || tbl || $$_update_trigger AFTER UPDATE OR DELETE ON $$ || sch || $$.$$ || tbl || $$ FOR EACH ROW EXECUTE PROCEDURE auditor.audit_$$ || sch || $$_$$ || tbl || $$_func (); $$; RETURN TRUE; END;
Function: auditor.fix_columns()
Returns: void
Language: PLPGSQL
DECLARE current_table TEXT = ''; -- Storage for post-loop main table name current_audit_table TEXT = ''; -- Storage for post-loop audit table name query TEXT = ''; -- Storage for built query cr RECORD; -- column record object alter_t BOOL = false; -- Has the alter table command been appended yet auditor_cores TEXT[] = ARRAY[]::TEXT[]; -- Core auditor function list (filled inside of loop) core_column TEXT; -- The current core column we are adding BEGIN FOR cr IN WITH audit_tables AS ( -- Basic grab of auditor tables. Anything in the auditor namespace, basically. With oids. SELECT c.oid AS audit_oid, c.relname AS audit_table FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE relkind='r' AND nspname = 'auditor' ), table_set AS ( -- Union of auditor tables with their "main" tables. With oids. SELECT a.audit_oid, a.audit_table, c.oid AS main_oid, n.nspname as main_namespace, c.relname as main_table FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace JOIN audit_tables a ON a.audit_table = n.nspname || '_' || c.relname || '_history' WHERE relkind = 'r' ), column_lists AS ( -- All columns associated with the auditor or main table, grouped by the main table's oid. SELECT DISTINCT ON (main_oid, attname) t.main_oid, a.attname FROM table_set t JOIN pg_catalog.pg_attribute a ON a.attrelid IN (t.main_oid, t.audit_oid) WHERE attnum > 0 AND NOT attisdropped ), column_defs AS ( -- The motherload, every audit table and main table plus column names and defs. SELECT audit_table, main_namespace, main_table, a.attname AS main_column, -- These two will be null for columns that have since been deleted, or for auditor core columns pg_catalog.format_type(a.atttypid, a.atttypmod) AS main_column_def, b.attname AS audit_column, -- These two will be null for columns that have since been added pg_catalog.format_type(b.atttypid, b.atttypmod) AS audit_column_def FROM table_set t JOIN column_lists c USING (main_oid) LEFT JOIN pg_catalog.pg_attribute a ON a.attname = c.attname AND a.attrelid = t.main_oid AND a.attnum > 0 AND NOT a.attisdropped LEFT JOIN pg_catalog.pg_attribute b ON b.attname = c.attname AND b.attrelid = t.audit_oid AND b.attnum > 0 AND NOT b.attisdropped ) -- Nice sorted output from the above SELECT * FROM column_defs WHERE main_column_def IS DISTINCT FROM audit_column_def ORDER BY main_namespace, main_table, main_column, audit_column LOOP IF current_table <> (cr.main_namespace || '.' || cr.main_table) THEN -- New table? FOR core_column IN SELECT DISTINCT unnest(auditor_cores) LOOP -- Update missing core auditor columns IF NOT alter_t THEN -- Add ALTER TABLE if we haven't already query:=query || $$ALTER TABLE auditor.$$ || current_audit_table; alter_t:=TRUE; ELSE query:=query || $$,$$; END IF; -- Bit of a sneaky bit here. Create audit_id as a bigserial so it gets automatic values and doesn't complain about nulls when becoming a PRIMARY KEY. query:=query || $$ ADD COLUMN $$ || CASE WHEN core_column = 'audit_id bigint' THEN $$audit_id bigserial PRIMARY KEY$$ ELSE core_column END; END LOOP; IF alter_t THEN -- Open alter table = needs a semicolon query:=query || $$; $$; alter_t:=FALSE; IF 'audit_id bigint' = ANY(auditor_cores) THEN -- We added a primary key... -- Fun! Drop the default on audit_id, drop the auto-created sequence, create a new one, and set the current value -- For added fun, we have to execute in chunks due to the parser checking setval/currval arguments at parse time. EXECUTE query; EXECUTE $$ALTER TABLE auditor.$$ || current_audit_table || $$ ALTER COLUMN audit_id DROP DEFAULT; $$ || $$CREATE SEQUENCE auditor.$$ || current_audit_table || $$_pkey_seq;$$; EXECUTE $$SELECT setval('auditor.$$ || current_audit_table || $$_pkey_seq', currval('auditor.$$ || current_audit_table || $$_audit_id_seq')); $$ || $$DROP SEQUENCE auditor.$$ || current_audit_table || $$_audit_id_seq;$$; query:=''; END IF; END IF; -- New table means we reset the list of needed auditor core columns auditor_cores = ARRAY['audit_id bigint', 'audit_time timestamp with time zone', 'audit_action text', 'audit_user integer', 'audit_ws integer']; -- And store some values for use later, because we can't rely on cr in all places. current_table:=cr.main_namespace || '.' || cr.main_table; current_audit_table:=cr.audit_table; END IF; IF cr.main_column IS NULL AND cr.audit_column LIKE 'audit_%' THEN -- Core auditor column? -- Remove core from list of cores SELECT INTO auditor_cores array_agg(core) FROM unnest(auditor_cores) AS core WHERE core != (cr.audit_column || ' ' || cr.audit_column_def); ELSIF cr.main_column IS NULL THEN -- Main column doesn't exist, and it isn't an auditor column. Needs dropping from the auditor. IF NOT alter_t THEN query:=query || $$ALTER TABLE auditor.$$ || current_audit_table; alter_t:=TRUE; ELSE query:=query || $$,$$; END IF; query:=query || $$ DROP COLUMN $$ || cr.audit_column; ELSIF cr.audit_column IS NULL AND cr.main_column IS NOT NULL THEN -- New column auditor doesn't have. Add it. IF NOT alter_t THEN query:=query || $$ALTER TABLE auditor.$$ || current_audit_table; alter_t:=TRUE; ELSE query:=query || $$,$$; END IF; query:=query || $$ ADD COLUMN $$ || cr.main_column || $$ $$ || cr.main_column_def; ELSIF cr.main_column IS NOT NULL AND cr.audit_column IS NOT NULL THEN -- Both sides have this column, but types differ. Fix that. IF NOT alter_t THEN query:=query || $$ALTER TABLE auditor.$$ || current_audit_table; alter_t:=TRUE; ELSE query:=query || $$,$$; END IF; query:=query || $$ ALTER COLUMN $$ || cr.audit_column || $$ TYPE $$ || cr.main_column_def; END IF; END LOOP; FOR core_column IN SELECT DISTINCT unnest(auditor_cores) LOOP -- Repeat this outside of the loop to catch the last table IF NOT alter_t THEN query:=query || $$ALTER TABLE auditor.$$ || current_audit_table; alter_t:=TRUE; ELSE query:=query || $$,$$; END IF; -- Bit of a sneaky bit here. Create audit_id as a bigserial so it gets automatic values and doesn't complain about nulls when becoming a PRIMARY KEY. query:=query || $$ ADD COLUMN $$ || CASE WHEN core_column = 'audit_id bigint' THEN $$audit_id bigserial PRIMARY KEY$$ ELSE core_column END; END LOOP; IF alter_t THEN -- Open alter table = needs a semicolon query:=query || $$;$$; IF 'audit_id bigint' = ANY(auditor_cores) THEN -- We added a primary key... -- Fun! Drop the default on audit_id, drop the auto-created sequence, create a new one, and set the current value -- For added fun, we have to execute in chunks due to the parser checking setval/currval arguments at parse time. EXECUTE query; EXECUTE $$ALTER TABLE auditor.$$ || current_audit_table || $$ ALTER COLUMN audit_id DROP DEFAULT; $$ || $$CREATE SEQUENCE auditor.$$ || current_audit_table || $$_pkey_seq;$$; EXECUTE $$SELECT setval('auditor.$$ || current_audit_table || $$_pkey_seq', currval('auditor.$$ || current_audit_table || $$_audit_id_seq')); $$ || $$DROP SEQUENCE auditor.$$ || current_audit_table || $$_audit_id_seq;$$; query:=''; END IF; END IF; EXECUTE query; END;
Function: auditor.get_audit_info()
Returns: SET OF record
Language: PLPERLU
return [{eg_user => $_SHARED{"eg_audit_user"}, eg_ws => $_SHARED{"eg_audit_ws"}}];
Function: auditor.set_audit_info(integer, integer)
Returns: void
Language: PLPERLU
$_SHARED{"eg_audit_user"} = $_[0]; $_SHARED{"eg_audit_ws"} = $_[1];
Function: auditor.update_auditors()
Returns: boolean
Language: PLPGSQL
DECLARE auditor_name TEXT; table_schema TEXT; table_name TEXT; BEGIN -- Drop Lifecycle view(s) before potential column changes FOR auditor_name IN SELECT c.relname FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE relkind = 'v' AND n.nspname = 'auditor' LOOP EXECUTE $$ DROP VIEW auditor.$$ || auditor_name || $$;$$; END LOOP; -- Fix all column discrepencies PERFORM auditor.fix_columns(); -- Re-create trigger functions and lifecycle views FOR table_schema, table_name IN WITH audit_tables AS ( SELECT c.oid AS audit_oid, c.relname AS audit_table FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE relkind='r' AND nspname = 'auditor' ), table_set AS ( SELECT a.audit_oid, a.audit_table, c.oid AS main_oid, n.nspname as main_namespace, c.relname as main_table FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace JOIN audit_tables a ON a.audit_table = n.nspname || '_' || c.relname || '_history' WHERE relkind = 'r' ) SELECT main_namespace, main_table FROM table_set LOOP PERFORM auditor.create_auditor_func(table_schema, table_name); PERFORM auditor.create_auditor_lifecycle(table_schema, table_name); END LOOP; RETURN TRUE; END;
Schema authority
Table: authority.authority_linking
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
authority.record_entry.id | source | bigint | NOT NULL |
authority.record_entry.id | target | bigint | NOT NULL |
authority.control_set_authority_field.id | field | integer | NOT NULL |
Table: authority.bib_linking
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
biblio.record_entry.id | bib | bigint | NOT NULL |
authority.record_entry.id | authority | bigint | NOT NULL |
Table: authority.browse_axis
F-Key | Name | Type | Description |
---|---|---|---|
code | text | PRIMARY KEY | |
name | text | UNIQUE NOT NULL | |
config.record_attr_definition.name | sorter | text | |
description | text |
Tables referencing this one via Foreign Key Constraints:
Table: authority.browse_axis_authority_field_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
authority.browse_axis.code | axis | text | NOT NULL |
authority.control_set_authority_field.id | field | integer | NOT NULL |
Table: authority.control_set
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE NOT NULL | |
description | text |
Tables referencing this one via Foreign Key Constraints:
View: authority.control_set_auth_field_metabib_field_map_blind_main
metabib fields for main entry auth fields that can't be linked to other records
F-Key | Name | Type | Description |
---|---|---|---|
authority_field | integer | ||
metabib_field | integer |
SELECT r.authority_field , r.metabib_field FROM (authority.control_set_auth_field_metabib_field_map_main r JOIN authority.control_set_authority_field a ON ( (r.authority_field = a.id) ) ) WHERE (a.linking_subfield IS NULL);
View: authority.control_set_auth_field_metabib_field_map_blind_refs
metabib fields for all auth fields that can't be linked to other records
F-Key | Name | Type | Description |
---|---|---|---|
authority_field | integer | ||
metabib_field | integer |
SELECT r.authority_field , r.metabib_field FROM (authority.control_set_auth_field_metabib_field_map_refs r JOIN authority.control_set_authority_field a ON ( (r.authority_field = a.id) ) ) WHERE (a.linking_subfield IS NULL);
View: authority.control_set_auth_field_metabib_field_map_blind_refs_only
metabib fields for NON-main entry auth fields that can't be linked to other records
F-Key | Name | Type | Description |
---|---|---|---|
authority_field | integer | ||
metabib_field | integer |
SELECT r.authority_field , r.metabib_field FROM (authority.control_set_auth_field_metabib_field_map_refs_only r JOIN authority.control_set_authority_field a ON ( (r.authority_field = a.id) ) ) WHERE (a.linking_subfield IS NULL);
View: authority.control_set_auth_field_metabib_field_map_main
metabib fields for main entry auth fields
F-Key | Name | Type | Description |
---|---|---|---|
authority_field | integer | ||
metabib_field | integer |
SELECT DISTINCT b.authority_field , m.metabib_field FROM (authority.control_set_bib_field_metabib_field_map m JOIN authority.control_set_bib_field b ON ( (b.id = m.bib_field) ) );
View: authority.control_set_auth_field_metabib_field_map_refs
metabib fields for all auth fields
F-Key | Name | Type | Description |
---|---|---|---|
authority_field | integer | ||
metabib_field | integer |
SELECT control_set_auth_field_metabib_field_map_main.authority_field , control_set_auth_field_metabib_field_map_main.metabib_field FROM authority.control_set_auth_field_metabib_field_map_main UNION SELECT control_set_auth_field_metabib_field_map_refs_only.authority_field , control_set_auth_field_metabib_field_map_refs_only.metabib_field FROM authority.control_set_auth_field_metabib_field_map_refs_only;
View: authority.control_set_auth_field_metabib_field_map_refs_only
metabib fields for NON-main entry auth fields
F-Key | Name | Type | Description |
---|---|---|---|
authority_field | integer | ||
metabib_field | integer |
SELECT DISTINCT a.id AS authority_field , m.metabib_field FROM ( ( ( (authority.control_set_authority_field a JOIN authority.control_set_authority_field ame ON ( (a.main_entry = ame.id) ) ) JOIN authority.control_set_bib_field b ON ( (b.authority_field = ame.id) ) ) JOIN authority.control_set_bib_field_metabib_field_map mf ON ( (mf.bib_field = b.id) ) ) JOIN authority.control_set_auth_field_metabib_field_map_main m ON ( (ame.id = m.authority_field) ) );
Table: authority.control_set_authority_field
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
authority.control_set_authority_field.id | main_entry | integer | |
authority.control_set.id | control_set | integer | NOT NULL |
tag | character(3) | NOT NULL | |
nfi | character(1) | ||
sf_list | text | NOT NULL | |
display_sf_list | text | NOT NULL | |
name | text | NOT NULL | |
description | text | ||
joiner | text | ||
linking_subfield | character(1) | ||
authority.heading_field.id | heading_field | integer |
Tables referencing this one via Foreign Key Constraints:
Table: authority.control_set_bib_field
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
authority.control_set_authority_field.id | authority_field | integer | NOT NULL |
tag | character(3) | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: authority.control_set_bib_field_metabib_field_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
authority.control_set_bib_field.id | bib_field | integer | UNIQUE#1 NOT NULL |
config.metabib_field.id | metabib_field | integer | UNIQUE#1 NOT NULL |
Table: authority.full_rec
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
record | bigint | NOT NULL | |
tag | character(3) | NOT NULL | |
ind1 | text | ||
ind2 | text | ||
subfield | text | ||
value | text | NOT NULL | |
index_vector | tsvector | NOT NULL |
Table: authority.heading_field
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
heading_type | authority.heading_type | NOT NULL | |
heading_purpose | authority.heading_purpose | NOT NULL | |
label | text | NOT NULL | |
config.xml_transform.name | format | text | NOT NULL DEFAULT 'mads21'::text |
heading_xpath | text | NOT NULL | |
component_xpath | text | NOT NULL | |
type_xpath | text | ||
thesaurus_xpath | text | ||
thesaurus_override_xpath | text | ||
joiner | text |
Tables referencing this one via Foreign Key Constraints:
Table: authority.heading_field_norm_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
authority.heading_field.id | field | integer | NOT NULL |
config.index_normalizer.id | norm | integer | NOT NULL |
params | text | ||
pos | integer | NOT NULL |
Table: authority.rec_descriptor
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
record | bigint | ||
record_status | text | ||
encoding_level | text | ||
thesaurus | text |
Table: authority.record_entry
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
create_date | timestamp with time zone | NOT NULL DEFAULT now() | |
edit_date | timestamp with time zone | NOT NULL DEFAULT now() | |
creator | integer | NOT NULL DEFAULT 1 | |
editor | integer | NOT NULL DEFAULT 1 | |
active | boolean | NOT NULL DEFAULT true | |
deleted | boolean | NOT NULL DEFAULT false | |
source | integer | ||
authority.control_set.id | control_set | integer | |
marc | text | NOT NULL | |
last_xact_id | text | NOT NULL | |
owner | integer | ||
heading | text | ||
simple_heading | text |
Tables referencing this one via Foreign Key Constraints:
authority_record_deleted_idx deleted) WHERE ((deleted IS FALSE) OR (deleted = false) authority_record_entry_create_date_idx create_date authority_record_entry_creator_idx creator authority_record_entry_edit_date_idx edit_date authority_record_entry_editor_idx editor by_heading simple_heading) WHERE ((deleted IS FALSE) OR (deleted = false) by_heading_and_thesaurus heading) WHERE ((deleted IS FALSE) OR (deleted = false)Table: authority.record_note
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
authority.record_entry.id | record | bigint | NOT NULL |
value | text | NOT NULL | |
creator | integer | NOT NULL DEFAULT 1 | |
editor | integer | NOT NULL DEFAULT 1 | |
create_date | timestamp with time zone | NOT NULL DEFAULT now() | |
edit_date | timestamp with time zone | NOT NULL DEFAULT now() |
Table: authority.simple_heading
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
authority.record_entry.id | record | bigint | NOT NULL |
authority.control_set_authority_field.id | atag | integer | NOT NULL |
value | text | NOT NULL | |
sort_value | text | NOT NULL | |
index_vector | tsvector | NOT NULL | |
thesaurus | text |
Tables referencing this one via Foreign Key Constraints:
authority_simple_heading_index_vector_idx index_vector authority_simple_heading_record_idx record authority_simple_heading_sort_value_idx sort_value authority_simple_heading_thesaurus_idx thesaurus authority_simple_heading_value_idx valueTable: authority.thesaurus
F-Key | Name | Type | Description |
---|---|---|---|
code | text | PRIMARY KEY | |
authority.control_set.id | control_set | integer | |
name | text | UNIQUE NOT NULL | |
description | text | ||
short_code | text | ||
uri | text |
View: authority.tracing_links
F-Key | Name | Type | Description |
---|---|---|---|
record | bigint | ||
main_id | bigint | ||
main_tag | character(3) | ||
main_value | text | ||
relationship | text | ||
use_restriction | text | ||
deprecation | text | ||
display_restriction | text | ||
link_id | bigint | ||
link_tag | character(3) | ||
link_value | text | ||
normalized_main_value | text |
SELECT main.record , main.id AS main_id , main.tag AS main_tag , oils_xpath_string ( ( ('//*[@tag="'::text || (main.tag)::text ) || '"]/*[local-name()="subfield"]'::text ) , are.marc ) AS main_value , substr ( link.value , 1 , 1 ) AS relationship , substr ( link.value , 2 , 1 ) AS use_restriction , substr ( link.value , 3 , 1 ) AS deprecation , substr ( link.value , 4 , 1 ) AS display_restriction , link.id AS link_id , link.tag AS link_tag , oils_xpath_string ( ( ('//*[@tag="'::text || (link.tag)::text ) || '"]/*[local-name()="subfield"]'::text ) , are.marc ) AS link_value , are.heading AS normalized_main_value FROM ( ( ( (authority.full_rec main JOIN authority.record_entry are ON ( (main.record = are.id) ) ) JOIN authority.control_set_authority_field main_entry ON ( ( (main_entry.tag = main.tag) AND (main_entry.main_entry IS NULL) AND (main.subfield = 'a'::text) ) ) ) JOIN authority.control_set_authority_field sub_entry ON ( (main_entry.id = sub_entry.main_entry) ) ) JOIN authority.full_rec link ON ( ( (link.record = main.record) AND (link.tag = sub_entry.tag) AND (link.subfield = 'w'::text) ) ) ) ;
Function: authority.atag_authority_tags(atag text)
Returns: integer[]
Language: SQL
SELECT ARRAY_AGG(id) FROM authority.control_set_authority_field WHERE tag = $1
Function: authority.atag_authority_tags_refs(atag text)
Returns: integer[]
Language: SQL
SELECT ARRAY_AGG(y) from ( SELECT unnest(ARRAY_CAT( ARRAY[a.id], (SELECT ARRAY_AGG(x.id) FROM authority.control_set_authority_field x WHERE x.main_entry = a.id) )) y FROM authority.control_set_authority_field a WHERE a.tag = $1) x
Function: authority.atag_browse_center(thesauruses text, pagesize text, page integer, q integer, a text)
Returns: SET OF bigint
Language: SQL
SELECT * FROM authority.simple_heading_browse_center(authority.atag_authority_tags($1), $2, $3, $4, $5)
Function: authority.atag_browse_center_refs(thesauruses text, pagesize text, page integer, q integer, a text)
Returns: SET OF bigint
Language: SQL
SELECT * FROM authority.simple_heading_browse_center(authority.atag_authority_tags_refs($1), $2, $3, $4, $5)
Function: authority.atag_browse_top(thesauruses text, pagesize text, page integer, q integer, a text)
Returns: SET OF bigint
Language: SQL
SELECT * FROM authority.simple_heading_browse_top(authority.atag_authority_tags($1), $2, $3, $4, $5)
Function: authority.atag_browse_top_refs(thesauruses text, pagesize text, page integer, q integer, a text)
Returns: SET OF bigint
Language: SQL
SELECT * FROM authority.simple_heading_browse_top(authority.atag_authority_tags_refs($1), $2, $3, $4, $5)
Function: authority.atag_search_heading(thesauruses text, pagesize text, page integer, q integer, a text)
Returns: SET OF bigint
Language: SQL
SELECT * FROM authority.simple_heading_search_heading(authority.atag_authority_tags($1), $2, $3, $4, $5)
Function: authority.atag_search_heading_refs(thesauruses text, pagesize text, page integer, q integer, a text)
Returns: SET OF bigint
Language: SQL
SELECT * FROM authority.simple_heading_search_heading(authority.atag_authority_tags_refs($1), $2, $3, $4, $5)
Function: authority.atag_search_rank(thesauruses text, pagesize text, page integer, q integer, a text)
Returns: SET OF bigint
Language: SQL
SELECT * FROM authority.simple_heading_search_rank(authority.atag_authority_tags($1), $2, $3, $4, $5)
Function: authority.atag_search_rank_refs(thesauruses text, pagesize text, page integer, q integer, a text)
Returns: SET OF bigint
Language: SQL
SELECT * FROM authority.simple_heading_search_rank(authority.atag_authority_tags_refs($1), $2, $3, $4, $5)
Function: authority.axis_authority_tags(a text)
Returns: integer[]
Language: SQL
SELECT ARRAY_AGG(field) FROM authority.browse_axis_authority_field_map WHERE axis = $1;
Function: authority.axis_authority_tags_refs(a text)
Returns: integer[]
Language: SQL
SELECT ARRAY_AGG(y) from ( SELECT unnest(ARRAY_CAT( ARRAY[a.field], (SELECT ARRAY_AGG(x.id) FROM authority.control_set_authority_field x WHERE x.main_entry = a.field) )) y FROM authority.browse_axis_authority_field_map a WHERE axis = $1) x
Function: authority.axis_browse_center(thesauruses text, pagesize text, page integer, q integer, a text)
Returns: SET OF bigint
Language: SQL
SELECT * FROM authority.simple_heading_browse_center(authority.axis_authority_tags($1), $2, $3, $4, $5)
Function: authority.axis_browse_center_refs(thesauruses text, pagesize text, page integer, q integer, a text)
Returns: SET OF bigint
Language: SQL
SELECT * FROM authority.simple_heading_browse_center(authority.axis_authority_tags_refs($1), $2, $3, $4, $5)
Function: authority.axis_browse_top(thesauruses text, pagesize text, page integer, q integer, a text)
Returns: SET OF bigint
Language: SQL
SELECT * FROM authority.simple_heading_browse_top(authority.axis_authority_tags($1), $2, $3, $4, $5)
Function: authority.axis_browse_top_refs(thesauruses text, pagesize text, page integer, q integer, a text)
Returns: SET OF bigint
Language: SQL
SELECT * FROM authority.simple_heading_browse_top(authority.axis_authority_tags_refs($1), $2, $3, $4, $5)
Function: authority.axis_search_heading(thesauruses text, pagesize text, page integer, q integer, a text)
Returns: SET OF bigint
Language: SQL
SELECT * FROM authority.simple_heading_search_heading(authority.axis_authority_tags($1), $2, $3, $4, $5)
Function: authority.axis_search_heading_refs(thesauruses text, pagesize text, page integer, q integer, a text)
Returns: SET OF bigint
Language: SQL
SELECT * FROM authority.simple_heading_search_heading(authority.axis_authority_tags_refs($1), $2, $3, $4, $5)
Function: authority.axis_search_rank(thesauruses text, pagesize text, page integer, q integer, a text)
Returns: SET OF bigint
Language: SQL
SELECT * FROM authority.simple_heading_search_rank(authority.axis_authority_tags($1), $2, $3, $4, $5)
Function: authority.axis_search_rank_refs(thesauruses text, pagesize text, page integer, q integer, a text)
Returns: SET OF bigint
Language: SQL
SELECT * FROM authority.simple_heading_search_rank(authority.axis_authority_tags_refs($1), $2, $3, $4, $5)
Function: authority.btag_authority_tags(btag text)
Returns: integer[]
Language: SQL
SELECT ARRAY_AGG(authority_field) FROM authority.control_set_bib_field WHERE tag = $1
Function: authority.btag_authority_tags_refs(btag text)
Returns: integer[]
Language: SQL
SELECT ARRAY_AGG(y) from ( SELECT unnest(ARRAY_CAT( ARRAY[a.authority_field], (SELECT ARRAY_AGG(x.id) FROM authority.control_set_authority_field x WHERE x.main_entry = a.authority_field) )) y FROM authority.control_set_bib_field a WHERE a.tag = $1) x
Function: authority.btag_browse_center(thesauruses text, pagesize text, page integer, q integer, a text)
Returns: SET OF bigint
Language: SQL
SELECT * FROM authority.simple_heading_browse_center(authority.btag_authority_tags($1), $2, $3, $4, $5)
Function: authority.btag_browse_center_refs(thesauruses text, pagesize text, page integer, q integer, a text)
Returns: SET OF bigint
Language: SQL
SELECT * FROM authority.simple_heading_browse_center(authority.btag_authority_tags_refs($1), $2, $3, $4, $5)
Function: authority.btag_browse_top(thesauruses text, pagesize text, page integer, q integer, a text)
Returns: SET OF bigint
Language: SQL
SELECT * FROM authority.simple_heading_browse_top(authority.btag_authority_tags($1), $2, $3, $4, $5)
Function: authority.btag_browse_top_refs(thesauruses text, pagesize text, page integer, q integer, a text)
Returns: SET OF bigint
Language: SQL
SELECT * FROM authority.simple_heading_browse_top(authority.btag_authority_tags_refs($1), $2, $3, $4, $5)
Function: authority.btag_search_heading(thesauruses text, pagesize text, page integer, q integer, a text)
Returns: SET OF bigint
Language: SQL
SELECT * FROM authority.simple_heading_search_heading(authority.btag_authority_tags($1), $2, $3, $4, $5)
Function: authority.btag_search_heading_refs(thesauruses text, pagesize text, page integer, q integer, a text)
Returns: SET OF bigint
Language: SQL
SELECT * FROM authority.simple_heading_search_heading(authority.btag_authority_tags_refs($1), $2, $3, $4, $5)
Function: authority.btag_search_rank(thesauruses text, pagesize text, page integer, q integer, a text)
Returns: SET OF bigint
Language: SQL
SELECT * FROM authority.simple_heading_search_rank(authority.btag_authority_tags($1), $2, $3, $4, $5)
Function: authority.btag_search_rank_refs(thesauruses text, pagesize text, page integer, q integer, a text)
Returns: SET OF bigint
Language: SQL
SELECT * FROM authority.simple_heading_search_rank(authority.btag_authority_tags_refs($1), $2, $3, $4, $5)
Function: authority.calculate_authority_linking(rec_marc_xml bigint, rec_control_set integer, rec_id xml)
Returns: SET OF authority_linking
Language: PLPGSQL
DECLARE acsaf authority.control_set_authority_field%ROWTYPE; link TEXT; aal authority.authority_linking%ROWTYPE; BEGIN IF rec_control_set IS NULL THEN -- No control_set on record? Guess at one SELECT control_set INTO rec_control_set FROM authority.control_set_authority_field WHERE tag IN ( SELECT UNNEST( XPATH('//*[starts-with(@tag,"1")]/@tag',rec_marc_xml)::TEXT[] ) ) LIMIT 1; IF NOT FOUND THEN RAISE WARNING 'Could not even guess at control set for authority record %', rec_id; RETURN; END IF; END IF; aal.source := rec_id; FOR acsaf IN SELECT * FROM authority.control_set_authority_field WHERE control_set = rec_control_set AND linking_subfield IS NOT NULL AND main_entry IS NOT NULL LOOP -- Loop over the trailing-number contents of all linking subfields FOR link IN SELECT SUBSTRING( x::TEXT, '\d+$' ) FROM UNNEST( XPATH( '//*[@tag="' || acsaf.tag || '"]/*[@code="' || acsaf.linking_subfield || '"]/text()', rec_marc_xml ) ) x LOOP -- Ignore links that are null, malformed, circular, or point to -- non-existent authority records. IF link IS NOT NULL AND link::BIGINT <> rec_id THEN PERFORM * FROM authority.record_entry WHERE id = link::BIGINT; IF FOUND THEN aal.target := link::BIGINT; aal.field := acsaf.id; RETURN NEXT aal; END IF; END IF; END LOOP; END LOOP; END;
Function: authority.extract_headings(restrict bigint, rid integer[])
Returns: SET OF heading
Language: PLPGSQL
DECLARE auth authority.record_entry%ROWTYPE; output_row authority.heading; BEGIN -- Get the record SELECT INTO auth * FROM authority.record_entry WHERE id = rid; RETURN QUERY SELECT * FROM authority.extract_headings(auth.marc, restrict); END;
Function: authority.extract_headings(restrict text, marc integer[])
Returns: SET OF heading
Language: PLPGSQL
DECLARE idx authority.heading_field%ROWTYPE; xfrm config.xml_transform%ROWTYPE; prev_xfrm TEXT; transformed_xml TEXT; heading_node TEXT; heading_node_list TEXT[]; component_node TEXT; component_node_list TEXT[]; raw_text TEXT; normalized_text TEXT; normalizer RECORD; curr_text TEXT; joiner TEXT; type_value TEXT; base_thesaurus TEXT := NULL; output_row authority.heading; BEGIN -- Loop over the indexing entries FOR idx IN SELECT * FROM authority.heading_field WHERE restrict IS NULL OR id = ANY (restrict) ORDER BY format LOOP output_row.field := idx.id; output_row.type := idx.heading_type; output_row.purpose := idx.heading_purpose; joiner := COALESCE(idx.joiner, ' '); SELECT INTO xfrm * from config.xml_transform WHERE name = idx.format; -- See if we can skip the XSLT ... it's expensive IF prev_xfrm IS NULL OR prev_xfrm <> xfrm.name THEN -- Can't skip the transform IF xfrm.xslt <> '---' THEN transformed_xml := oils_xslt_process(marc, xfrm.xslt); ELSE transformed_xml := marc; END IF; prev_xfrm := xfrm.name; END IF; IF idx.thesaurus_xpath IS NOT NULL THEN base_thesaurus := ARRAY_TO_STRING(oils_xpath(idx.thesaurus_xpath, transformed_xml, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]]), ''); END IF; heading_node_list := oils_xpath( idx.heading_xpath, transformed_xml, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] ); FOR heading_node IN SELECT x FROM unnest(heading_node_list) AS x LOOP CONTINUE WHEN heading_node !~ E'^\\s*<'; output_row.variant_type := NULL; output_row.related_type := NULL; output_row.thesaurus := NULL; output_row.heading := NULL; IF idx.heading_purpose = 'variant' AND idx.type_xpath IS NOT NULL THEN type_value := ARRAY_TO_STRING(oils_xpath(idx.type_xpath, heading_node, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]]), ''); BEGIN output_row.variant_type := type_value; EXCEPTION WHEN invalid_text_representation THEN RAISE NOTICE 'Do not recognize variant heading type %', type_value; END; END IF; IF idx.heading_purpose = 'related' AND idx.type_xpath IS NOT NULL THEN type_value := ARRAY_TO_STRING(oils_xpath(idx.type_xpath, heading_node, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]]), ''); BEGIN output_row.related_type := type_value; EXCEPTION WHEN invalid_text_representation THEN RAISE NOTICE 'Do not recognize related heading type %', type_value; END; END IF; IF idx.thesaurus_override_xpath IS NOT NULL THEN output_row.thesaurus := ARRAY_TO_STRING(oils_xpath(idx.thesaurus_override_xpath, heading_node, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]]), ''); END IF; IF output_row.thesaurus IS NULL THEN output_row.thesaurus := base_thesaurus; END IF; raw_text := NULL; -- now iterate over components of heading component_node_list := oils_xpath( idx.component_xpath, heading_node, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] ); FOR component_node IN SELECT x FROM unnest(component_node_list) AS x LOOP -- XXX much of this should be moved into oils_xpath_string... curr_text := ARRAY_TO_STRING(array_remove(array_remove( oils_xpath( '//text()', -- get the content of all the nodes within the main selected node REGEXP_REPLACE( component_node, E'\\s+', ' ', 'g' ) -- Translate adjacent whitespace to a single space ), ' '), ''), -- throw away morally empty (bankrupt?) strings joiner ); CONTINUE WHEN curr_text IS NULL OR curr_text = ''; IF raw_text IS NOT NULL THEN raw_text := raw_text || joiner; END IF; raw_text := COALESCE(raw_text,'') || curr_text; END LOOP; IF raw_text IS NOT NULL THEN output_row.heading := raw_text; normalized_text := raw_text; FOR normalizer IN SELECT n.func AS func, n.param_count AS param_count, m.params AS params FROM config.index_normalizer n JOIN authority.heading_field_norm_map m ON (m.norm = n.id) WHERE m.field = idx.id ORDER BY m.pos LOOP EXECUTE 'SELECT ' || normalizer.func || '(' || quote_literal( normalized_text ) || CASE WHEN normalizer.param_count > 0 THEN ',' || REPLACE(REPLACE(BTRIM(normalizer.params,'[]'),E'\'',E'\\\''),E'"',E'\'') ELSE '' END || ')' INTO normalized_text; END LOOP; output_row.normalized_heading := normalized_text; RETURN NEXT output_row; END IF; END LOOP; END LOOP; END;
Function: authority.extract_thesaurus(marcxml text)
Returns: text
Language: PLPGSQL
DECLARE thes_code TEXT; BEGIN thes_code := vandelay.marc21_extract_fixed_field(marcxml,'Subj'); IF thes_code IS NULL THEN thes_code := '|'; ELSIF thes_code = 'z' THEN thes_code := COALESCE( oils_xpath_string('//*[@tag="040"]/*[@code="f"][1]', marcxml), 'z' ); ELSE SELECT code INTO thes_code FROM authority.thesaurus WHERE short_code = thes_code; IF NOT FOUND THEN thes_code := '|'; -- default END IF; END IF; RETURN thes_code; END;
Function: authority.flatten_marc(rid bigint)
Returns: SET OF full_rec
Language: PLPGSQL
DECLARE auth authority.record_entry%ROWTYPE; output authority.full_rec%ROWTYPE; field RECORD; BEGIN SELECT INTO auth * FROM authority.record_entry WHERE id = rid; FOR field IN SELECT * FROM vandelay.flatten_marc( auth.marc ) LOOP output.record := rid; output.ind1 := field.ind1; output.ind2 := field.ind2; output.tag := field.tag; output.subfield := field.subfield; output.value := field.value; RETURN NEXT output; END LOOP; END;
Function: authority.generate_overlay_template(bigint)
Returns: text
Language: SQL
SELECT authority.generate_overlay_template( marc ) FROM authority.record_entry WHERE id = $1;
Function: authority.generate_overlay_template(source_xml text)
Returns: text
Language: PLPGSQL
DECLARE cset INT; main_entry authority.control_set_authority_field%ROWTYPE; bib_field authority.control_set_bib_field%ROWTYPE; auth_id INT DEFAULT oils_xpath_string('//*[@tag="901"]/*[local-name()="subfield" and @code="c"]', source_xml)::INT; tmp_data XML; replace_data XML[] DEFAULT '{}'::XML[]; replace_rules TEXT[] DEFAULT '{}'::TEXT[]; auth_field XML[]; auth_i1 TEXT; auth_i2 TEXT; BEGIN IF auth_id IS NULL THEN RETURN NULL; END IF; -- Default to the LoC controll set SELECT control_set INTO cset FROM authority.record_entry WHERE id = auth_id; -- if none, make a best guess IF cset IS NULL THEN SELECT control_set INTO cset FROM authority.control_set_authority_field WHERE tag IN ( SELECT UNNEST(XPATH('//*[local-name()="datafield" and starts-with(@tag,"1")]/@tag',marc::XML)::TEXT[]) FROM authority.record_entry WHERE id = auth_id ) LIMIT 1; END IF; -- if STILL none, no-op change IF cset IS NULL THEN RETURN XMLELEMENT( name record, XMLATTRIBUTES('http://www.loc.gov/MARC21/slim' AS xmlns), XMLELEMENT( name leader, '00881nam a2200193 4500'), XMLELEMENT( name datafield, XMLATTRIBUTES( '905' AS tag, ' ' AS ind1, ' ' AS ind2), XMLELEMENT( name subfield, XMLATTRIBUTES('d' AS code), '901c' ) ) )::TEXT; END IF; FOR main_entry IN SELECT * FROM authority.control_set_authority_field acsaf WHERE acsaf.control_set = cset AND acsaf.main_entry IS NULL LOOP auth_field := XPATH('//*[local-name()="datafield" and @tag="'||main_entry.tag||'"][1]',source_xml::XML); auth_i1 := (XPATH('//*[local-name()="datafield"]/@ind1',auth_field[1]))[1]; auth_i2 := (XPATH('//*[local-name()="datafield"]/@ind2',auth_field[1]))[1]; IF ARRAY_LENGTH(auth_field,1) > 0 THEN FOR bib_field IN SELECT * FROM authority.control_set_bib_field WHERE authority_field = main_entry.id LOOP SELECT XMLELEMENT( -- XMLAGG avoids magical <element> creation, but requires unnest subquery name datafield, XMLATTRIBUTES(bib_field.tag AS tag, auth_i1 AS ind1, auth_i2 AS ind2), XMLAGG(UNNEST) ) INTO tmp_data FROM UNNEST(XPATH('//*[local-name()="subfield"]', auth_field[1])); replace_data := replace_data || tmp_data; replace_rules := replace_rules || ( bib_field.tag || main_entry.sf_list || E'[0~\\)' || auth_id || '$]' ); tmp_data = NULL; END LOOP; EXIT; END IF; END LOOP; SELECT XMLAGG(UNNEST) INTO tmp_data FROM UNNEST(replace_data); RETURN XMLELEMENT( name record, XMLATTRIBUTES('http://www.loc.gov/MARC21/slim' AS xmlns), XMLELEMENT( name leader, '00881nam a2200193 4500'), tmp_data, XMLELEMENT( name datafield, XMLATTRIBUTES( '905' AS tag, ' ' AS ind1, ' ' AS ind2), XMLELEMENT( name subfield, XMLATTRIBUTES('r' AS code), ARRAY_TO_STRING(replace_rules,',') ) ) )::TEXT; END;
Function: authority.indexing_ingest_or_delete()
Returns: trigger
Language: PLPGSQL
DECLARE ashs authority.simple_heading%ROWTYPE; mbe_row metabib.browse_entry%ROWTYPE; mbe_id BIGINT; ash_id BIGINT; BEGIN IF NEW.deleted IS TRUE THEN -- If this authority is deleted DELETE FROM authority.bib_linking WHERE authority = NEW.id; -- Avoid updating fields in bibs that are no longer visible DELETE FROM authority.full_rec WHERE record = NEW.id; -- Avoid validating fields against deleted authority records DELETE FROM authority.simple_heading WHERE record = NEW.id; -- Should remove matching $0 from controlled fields at the same time? -- XXX What do we about the actual linking subfields present in -- authority records that target this one when this happens? DELETE FROM authority.authority_linking WHERE source = NEW.id OR target = NEW.id; RETURN NEW; -- and we're done END IF; IF TG_OP = 'UPDATE' THEN -- re-ingest? PERFORM * FROM config.internal_flag WHERE name = 'ingest.reingest.force_on_same_marc' AND enabled; IF NOT FOUND AND OLD.marc = NEW.marc THEN -- don't do anything if the MARC didn't change RETURN NEW; END IF; -- Unless there's a setting stopping us, propagate these updates to any linked bib records when the heading changes PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_authority_auto_update' AND enabled; IF NOT FOUND AND NEW.heading <> OLD.heading THEN PERFORM authority.propagate_changes(NEW.id); END IF; DELETE FROM authority.simple_heading WHERE record = NEW.id; DELETE FROM authority.authority_linking WHERE source = NEW.id; END IF; INSERT INTO authority.authority_linking (source, target, field) SELECT source, target, field FROM authority.calculate_authority_linking( NEW.id, NEW.control_set, NEW.marc::XML ); FOR ashs IN SELECT * FROM authority.simple_heading_set(NEW.marc) LOOP INSERT INTO authority.simple_heading (record,atag,value,sort_value,thesaurus) VALUES (ashs.record, ashs.atag, ashs.value, ashs.sort_value, ashs.thesaurus); ash_id := CURRVAL('authority.simple_heading_id_seq'::REGCLASS); SELECT INTO mbe_row * FROM metabib.browse_entry WHERE value = ashs.value AND sort_value = ashs.sort_value; IF FOUND THEN mbe_id := mbe_row.id; ELSE INSERT INTO metabib.browse_entry ( value, sort_value ) VALUES ( ashs.value, ashs.sort_value ); mbe_id := CURRVAL('metabib.browse_entry_id_seq'::REGCLASS); END IF; INSERT INTO metabib.browse_entry_simple_heading_map (entry,simple_heading) VALUES (mbe_id,ash_id); END LOOP; -- Flatten and insert the afr data PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_authority_full_rec' AND enabled; IF NOT FOUND THEN PERFORM authority.reingest_authority_full_rec(NEW.id); PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_authority_rec_descriptor' AND enabled; IF NOT FOUND THEN PERFORM authority.reingest_authority_rec_descriptor(NEW.id); END IF; END IF; RETURN NEW; END;
Function: authority.map_thesaurus_to_control_set()
Returns: trigger
Language: PLPGSQL
BEGIN IF NEW.control_set IS NULL THEN SELECT control_set INTO NEW.control_set FROM authority.thesaurus WHERE authority.extract_thesaurus(NEW.marc) = code; END IF; RETURN NEW; END;
Function: authority.merge_records(source_record bigint, target_record bigint)
Returns: integer
Language: PLPGSQL
DECLARE moved_objects INT := 0; bib_id INT := 0; bib_rec biblio.record_entry%ROWTYPE; auth_link authority.bib_linking%ROWTYPE; ingest_same boolean; BEGIN -- Defining our terms: -- "target record" = the record that will survive the merge -- "source record" = the record that is sacrifing its existence and being -- replaced by the target record -- 1. Update all bib records with the ID from target_record in their $0 FOR bib_rec IN SELECT bre.* FROM biblio.record_entry bre JOIN authority.bib_linking abl ON abl.bib = bre.id WHERE abl.authority = source_record LOOP UPDATE biblio.record_entry SET marc = REGEXP_REPLACE( marc, E'(<subfield\\s+code="0"\\s*>[^<]*?\\))' || source_record || '<', E'\\1' || target_record || '<', 'g' ) WHERE id = bib_rec.id; moved_objects := moved_objects + 1; END LOOP; -- 2. Grab the current value of reingest on same MARC flag SELECT enabled INTO ingest_same FROM config.internal_flag WHERE name = 'ingest.reingest.force_on_same_marc' ; -- 3. Temporarily set reingest on same to TRUE UPDATE config.internal_flag SET enabled = TRUE WHERE name = 'ingest.reingest.force_on_same_marc' ; -- 4. Make a harmless update to target_record to trigger auto-update -- in linked bibliographic records UPDATE authority.record_entry SET deleted = FALSE WHERE id = target_record; -- 5. "Delete" source_record DELETE FROM authority.record_entry WHERE id = source_record; -- 6. Set "reingest on same MARC" flag back to initial value UPDATE config.internal_flag SET enabled = ingest_same WHERE name = 'ingest.reingest.force_on_same_marc' ; RETURN moved_objects; END;
Function: authority.normalize_heading(marcxml text)
Returns: text
Language: SQL
Extract the authority heading, thesaurus, and NACO-normalized values from an authority record. The primary purpose is to build a unique index to defend against duplicated authority records from the same thesaurus.
SELECT authority.normalize_heading($1, FALSE);
Function: authority.normalize_heading(no_thesaurus text, marcxml boolean)
Returns: text
Language: PLPGSQL
DECLARE acsaf authority.control_set_authority_field%ROWTYPE; tag_used TEXT; nfi_used TEXT; sf TEXT; sf_node TEXT; tag_node TEXT; thes_code TEXT; cset INT; heading_text TEXT; tmp_text TEXT; first_sf BOOL; auth_id INT DEFAULT COALESCE(NULLIF(oils_xpath_string('//*[@tag="901"]/*[local-name()="subfield" and @code="c"]', marcxml), ''), '0')::INT; BEGIN SELECT control_set INTO cset FROM authority.record_entry WHERE id = auth_id; IF cset IS NULL THEN SELECT control_set INTO cset FROM authority.control_set_authority_field WHERE tag IN (SELECT UNNEST(XPATH('//*[starts-with(@tag,"1")]/@tag',marcxml::XML)::TEXT[])) LIMIT 1; END IF; heading_text := ''; FOR acsaf IN SELECT * FROM authority.control_set_authority_field WHERE control_set = cset AND main_entry IS NULL LOOP tag_used := acsaf.tag; nfi_used := acsaf.nfi; first_sf := TRUE; FOR tag_node IN SELECT unnest(oils_xpath('//*[@tag="'||tag_used||'"]',marcxml)) LOOP FOR sf_node IN SELECT unnest(oils_xpath('//*[local-name() = "subfield" and contains("'||acsaf.sf_list||'",@code)]',tag_node)) LOOP tmp_text := oils_xpath_string('.', sf_node); sf := oils_xpath_string('//*/@code', sf_node); IF first_sf AND tmp_text IS NOT NULL AND nfi_used IS NOT NULL THEN tmp_text := SUBSTRING( tmp_text FROM COALESCE( NULLIF( REGEXP_REPLACE( oils_xpath_string('//*[local-name() = "datafield"]/@ind'||nfi_used, tag_node), $$\D+$$, '', 'g' ), '' )::INT, 0 ) + 1 ); END IF; first_sf := FALSE; IF tmp_text IS NOT NULL AND tmp_text <> '' THEN heading_text := heading_text || E'\u2021' || sf || ' ' || tmp_text; END IF; END LOOP; EXIT WHEN heading_text <> ''; END LOOP; EXIT WHEN heading_text <> ''; END LOOP; IF heading_text <> '' THEN IF no_thesaurus IS TRUE THEN heading_text := tag_used || ' ' || public.naco_normalize(heading_text); ELSE thes_code := authority.extract_thesaurus(marcxml); heading_text := tag_used || '_' || COALESCE(nfi_used,'-') || '_' || thes_code || ' ' || public.naco_normalize(heading_text); END IF; ELSE heading_text := 'NOHEADING_' || thes_code || ' ' || MD5(marcxml); END IF; RETURN heading_text; END;
Function: authority.normalize_heading_for_upsert()
Returns: trigger
Language: PLPGSQL
BEGIN NEW.heading := authority.normalize_heading( NEW.marc ); NEW.simple_heading := authority.simple_normalize_heading( NEW.marc ); RETURN NEW; END;
Function: authority.propagate_changes(aid bigint)
Returns: SET OF bigint
Language: SQL
SELECT authority.propagate_changes( authority, bib ) FROM authority.bib_linking WHERE authority = $1;
Function: authority.propagate_changes(bid bigint, aid bigint)
Returns: bigint
Language: PLPGSQL
DECLARE bib_rec biblio.record_entry%ROWTYPE; new_marc TEXT; BEGIN SELECT INTO bib_rec * FROM biblio.record_entry WHERE id = bid; new_marc := vandelay.merge_record_xml( bib_rec.marc, authority.generate_overlay_template(aid)); IF new_marc = bib_rec.marc THEN -- Authority record change had no impact on this bib record. -- Nothing left to do. RETURN aid; END IF; PERFORM 1 FROM config.global_flag WHERE name = 'ingest.disable_authority_auto_update_bib_meta' AND enabled; IF NOT FOUND THEN -- update the bib record editor and edit_date bib_rec.editor := ( SELECT editor FROM authority.record_entry WHERE id = aid); bib_rec.edit_date = NOW(); END IF; UPDATE biblio.record_entry SET marc = new_marc, editor = bib_rec.editor, edit_date = bib_rec.edit_date WHERE id = bid; RETURN aid; END;
Function: authority.reingest_authority_full_rec(auth_id bigint)
Returns: void
Language: PLPGSQL
BEGIN DELETE FROM authority.full_rec WHERE record = auth_id; INSERT INTO authority.full_rec (record, tag, ind1, ind2, subfield, value) SELECT record, tag, ind1, ind2, subfield, value FROM authority.flatten_marc( auth_id ); RETURN; END;
Function: authority.reingest_authority_rec_descriptor(auth_id bigint)
Returns: void
Language: PLPGSQL
BEGIN DELETE FROM authority.rec_descriptor WHERE record = auth_id; INSERT INTO authority.rec_descriptor (record, record_status, encoding_level, thesaurus) SELECT auth_id, vandelay.marc21_extract_fixed_field(marc,'RecStat'), vandelay.marc21_extract_fixed_field(marc,'ELvl'), authority.extract_thesaurus(marc) FROM authority.record_entry WHERE id = auth_id; RETURN; END;
Function: authority.simple_heading_browse_center(thesauruses integer[], pagesize text, page integer, q integer, atag_list text)
Returns: SET OF bigint
Language: PLPGSQL
DECLARE pivot_sort_value TEXT; boffset INT DEFAULT 0; aoffset INT DEFAULT 0; blimit INT DEFAULT 0; alimit INT DEFAULT 0; BEGIN pivot_sort_value := authority.simple_heading_find_pivot(atag_list,q,thesauruses); IF page = 0 THEN blimit := pagesize / 2; alimit := blimit; IF pagesize % 2 <> 0 THEN alimit := alimit + 1; END IF; ELSE blimit := pagesize; alimit := blimit; boffset := pagesize / 2; aoffset := boffset; IF pagesize % 2 <> 0 THEN boffset := boffset + 1; END IF; END IF; IF page <= 0 THEN RETURN QUERY -- "bottom" half of the browse results SELECT id FROM ( SELECT ash.id, row_number() over () FROM authority.simple_heading ash WHERE ash.atag = ANY (atag_list) AND CASE thesauruses WHEN '' THEN TRUE ELSE ash.thesaurus = ANY(regexp_split_to_array(thesauruses, ',')) END AND ash.sort_value < pivot_sort_value ORDER BY ash.sort_value DESC LIMIT blimit OFFSET ABS(page) * pagesize - boffset ) x ORDER BY row_number DESC; END IF; IF page >= 0 THEN RETURN QUERY -- "bottom" half of the browse results SELECT ash.id FROM authority.simple_heading ash WHERE ash.atag = ANY (atag_list) AND CASE thesauruses WHEN '' THEN TRUE ELSE ash.thesaurus = ANY(regexp_split_to_array(thesauruses, ',')) END AND ash.sort_value >= pivot_sort_value ORDER BY ash.sort_value LIMIT alimit OFFSET ABS(page) * pagesize - aoffset; END IF; END;
Function: authority.simple_heading_browse_top(thesauruses integer[], pagesize text, page integer, q integer, atag_list text)
Returns: SET OF bigint
Language: PLPGSQL
DECLARE pivot_sort_value TEXT; BEGIN pivot_sort_value := authority.simple_heading_find_pivot(atag_list,q,thesauruses); IF page < 0 THEN RETURN QUERY -- "bottom" half of the browse results SELECT id FROM ( SELECT ash.id, row_number() over () FROM authority.simple_heading ash WHERE ash.atag = ANY (atag_list) AND CASE thesauruses WHEN '' THEN TRUE ELSE ash.thesaurus = ANY(regexp_split_to_array(thesauruses, ',')) END AND ash.sort_value < pivot_sort_value ORDER BY ash.sort_value DESC LIMIT pagesize OFFSET (ABS(page) - 1) * pagesize ) x ORDER BY row_number DESC; END IF; IF page >= 0 THEN RETURN QUERY -- "bottom" half of the browse results SELECT ash.id FROM authority.simple_heading ash WHERE ash.atag = ANY (atag_list) AND CASE thesauruses WHEN '' THEN TRUE ELSE ash.thesaurus = ANY(regexp_split_to_array(thesauruses, ',')) END AND ash.sort_value >= pivot_sort_value ORDER BY ash.sort_value LIMIT pagesize OFFSET ABS(page) * pagesize ; END IF; END;
Function: authority.simple_heading_find_pivot(thesauruses integer[], q text, a text)
Returns: text
Language: PLPGSQL
DECLARE sort_value_row RECORD; value_row RECORD; t_term TEXT; BEGIN t_term := public.naco_normalize(q); SELECT CASE WHEN ash.sort_value LIKE t_term || '%' THEN 1 ELSE 0 END + CASE WHEN ash.value LIKE t_term || '%' THEN 1 ELSE 0 END AS rank, ash.sort_value INTO sort_value_row FROM authority.simple_heading ash WHERE ash.atag = ANY (a) AND ash.sort_value >= t_term AND CASE thesauruses WHEN '' THEN TRUE ELSE ash.thesaurus = ANY(regexp_split_to_array(thesauruses, ',')) END ORDER BY rank DESC, ash.sort_value LIMIT 1; SELECT CASE WHEN ash.sort_value LIKE t_term || '%' THEN 1 ELSE 0 END + CASE WHEN ash.value LIKE t_term || '%' THEN 1 ELSE 0 END AS rank, ash.sort_value INTO value_row FROM authority.simple_heading ash WHERE ash.atag = ANY (a) AND ash.value >= t_term AND CASE thesauruses WHEN '' THEN TRUE ELSE ash.thesaurus = ANY(regexp_split_to_array(thesauruses, ',')) END ORDER BY rank DESC, ash.sort_value LIMIT 1; IF value_row.rank > sort_value_row.rank THEN RETURN value_row.sort_value; ELSE RETURN sort_value_row.sort_value; END IF; END;
Function: authority.simple_heading_search_heading(thesauruses integer[], pagesize text, page integer, q integer, atag_list text)
Returns: SET OF bigint
Language: SQL
SELECT ash.id FROM authority.simple_heading ash, public.naco_normalize($2) t(term), plainto_tsquery('keyword'::regconfig,$2) ptsq(term) WHERE ash.atag = ANY ($1) AND ash.index_vector @@ ptsq.term AND CASE $5 WHEN '' THEN TRUE ELSE ash.thesaurus = ANY(regexp_split_to_array($5, ',')) END ORDER BY ash.sort_value LIMIT $4 OFFSET $4 * $3;
Function: authority.simple_heading_search_rank(thesauruses integer[], pagesize text, page integer, q integer, atag_list text)
Returns: SET OF bigint
Language: SQL
SELECT ash.id FROM authority.simple_heading ash, public.naco_normalize($2) t(term), plainto_tsquery('keyword'::regconfig,$2) ptsq(term) WHERE ash.atag = ANY ($1) AND ash.index_vector @@ ptsq.term AND CASE $5 WHEN '' THEN TRUE ELSE ash.thesaurus = ANY(regexp_split_to_array($5, ',')) END ORDER BY ts_rank_cd(ash.index_vector,ptsq.term,14)::numeric + CASE WHEN ash.sort_value LIKE t.term || '%' THEN 2 ELSE 0 END + CASE WHEN ash.value LIKE t.term || '%' THEN 1 ELSE 0 END DESC LIMIT $4 OFFSET $4 * $3;
Function: authority.simple_heading_set(marcxml text)
Returns: SET OF simple_heading
Language: PLPGSQL
DECLARE res authority.simple_heading%ROWTYPE; acsaf authority.control_set_authority_field%ROWTYPE; heading_row authority.heading%ROWTYPE; tag_used TEXT; nfi_used TEXT; sf TEXT; cset INT; heading_text TEXT; joiner_text TEXT; sort_text TEXT; tmp_text TEXT; tmp_xml TEXT; first_sf BOOL; auth_id INT DEFAULT COALESCE(NULLIF(oils_xpath_string('//*[@tag="901"]/*[local-name()="subfield" and @code="c"]', marcxml), ''), '0')::INT; BEGIN SELECT control_set INTO cset FROM authority.record_entry WHERE id = auth_id; IF cset IS NULL THEN SELECT control_set INTO cset FROM authority.control_set_authority_field WHERE tag IN ( SELECT UNNEST(XPATH('//*[starts-with(@tag,"1")]/@tag',marcxml::XML)::TEXT[])) LIMIT 1; END IF; res.record := auth_id; res.thesaurus := authority.extract_thesaurus(marcxml); FOR acsaf IN SELECT * FROM authority.control_set_authority_field WHERE control_set = cset LOOP res.atag := acsaf.id; IF acsaf.heading_field IS NULL THEN tag_used := acsaf.tag; nfi_used := acsaf.nfi; joiner_text := COALESCE(acsaf.joiner, ' '); FOR tmp_xml IN SELECT UNNEST(XPATH('//*[@tag="'||tag_used||'"]', marcxml::XML)::TEXT[]) LOOP heading_text := COALESCE( oils_xpath_string('//*[local-name()="subfield" and contains("'||acsaf.display_sf_list||'",@code)]', tmp_xml, joiner_text), '' ); IF nfi_used IS NOT NULL THEN sort_text := SUBSTRING( heading_text FROM COALESCE( NULLIF( REGEXP_REPLACE( oils_xpath_string('//*[local-name()="datafield"]/@ind'||nfi_used, tmp_xml::TEXT), $$\D+$$, '', 'g' ), '' )::INT, 0 ) + 1 ); ELSE sort_text := heading_text; END IF; IF heading_text IS NOT NULL AND heading_text <> '' THEN res.value := heading_text; res.sort_value := public.naco_normalize(sort_text); res.index_vector = to_tsvector('keyword'::regconfig, res.sort_value); RETURN NEXT res; END IF; END LOOP; ELSE FOR heading_row IN SELECT * FROM authority.extract_headings(marcxml, ARRAY[acsaf.heading_field]) LOOP res.value := heading_row.heading; res.sort_value := heading_row.normalized_heading; res.index_vector = to_tsvector('keyword'::regconfig, res.sort_value); RETURN NEXT res; END LOOP; END IF; END LOOP; RETURN; END;
Function: authority.simple_normalize_heading(marcxml text)
Returns: text
Language: SQL
SELECT authority.normalize_heading($1, TRUE);
Schema biblio
Table: biblio.monograph_part
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
biblio.record_entry.id | record | bigint | NOT NULL |
label | text | NOT NULL | |
label_sortkey | text | NOT NULL | |
deleted | boolean | NOT NULL DEFAULT false |
Tables referencing this one via Foreign Key Constraints:
Table: biblio.peer_bib_copy_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
biblio.peer_type.id | peer_type | integer | NOT NULL |
biblio.record_entry.id | peer_record | bigint | NOT NULL |
target_copy | bigint | NOT NULL |
Table: biblio.peer_type
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: biblio.record_entry
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
actor.usr.id | creator | integer | NOT NULL DEFAULT 1 |
actor.usr.id | editor | integer | NOT NULL DEFAULT 1 |
source | integer | ||
quality | integer | ||
create_date | timestamp with time zone | NOT NULL DEFAULT now() | |
edit_date | timestamp with time zone | NOT NULL DEFAULT now() | |
active | boolean | NOT NULL DEFAULT true | |
deleted | boolean | NOT NULL DEFAULT false | |
fingerprint | text | ||
tcn_source | text | NOT NULL DEFAULT 'AUTOGEN'::text | |
tcn_value | text | NOT NULL DEFAULT biblio.next_autogen_tcn_value() | |
marc | text | NOT NULL | |
last_xact_id | text | NOT NULL | |
vis_attr_vector | integer[] | ||
actor.org_unit.id | owner | integer | |
share_depth | integer | ||
merge_date | timestamp with time zone | ||
biblio.record_entry.id | merged_to | bigint |
Tables referencing this one via Foreign Key Constraints:
biblio_record_entry_create_date_idx create_date biblio_record_entry_creator_idx creator biblio_record_entry_edit_date_idx edit_date biblio_record_entry_editor_idx editor biblio_record_entry_fp_idx fingerprintTable: biblio.record_note
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
biblio.record_entry.id | record | bigint | NOT NULL |
value | text | NOT NULL | |
actor.usr.id | creator | integer | NOT NULL DEFAULT 1 |
actor.usr.id | editor | integer | NOT NULL DEFAULT 1 |
deleted | boolean | NOT NULL DEFAULT false | |
create_date | timestamp with time zone | NOT NULL DEFAULT now() | |
edit_date | timestamp with time zone | NOT NULL DEFAULT now() |
Function: biblio.calculate_bib_visibility_attribute_set(force_source bigint, new_source integer, bib_id boolean)
Returns: integer[]
Language: PLPGSQL
DECLARE bib_row biblio.record_entry%ROWTYPE; cn_row asset.call_number%ROWTYPE; attr_set INT[] := '{}'::INT[]; BEGIN SELECT * INTO bib_row FROM biblio.record_entry WHERE id = bib_id; IF force_source THEN IF new_source IS NOT NULL THEN attr_set := attr_set || search.calculate_visibility_attribute(new_source, 'bib_source'); END IF; ELSIF bib_row.source IS NOT NULL THEN attr_set := attr_set || search.calculate_visibility_attribute(bib_row.source, 'bib_source'); END IF; FOR cn_row IN SELECT * FROM asset.call_number WHERE record = bib_id AND label = '##URI##' AND NOT deleted LOOP attr_set := attr_set || search.calculate_visibility_attribute(cn_row.owning_lib, 'luri_org'); END LOOP; RETURN attr_set; END;
Function: biblio.check_marcxml_well_formed()
Returns: trigger
Language: PLPGSQL
BEGIN IF xml_is_well_formed(NEW.marc) THEN RETURN NEW; ELSE RAISE EXCEPTION 'Attempted to % MARCXML that is not well formed', TG_OP; END IF; END;
Function: biblio.extract_fingerprint(marc text)
Returns: text
Language: PLPGSQL
DECLARE idx config.biblio_fingerprint%ROWTYPE; xfrm config.xml_transform%ROWTYPE; prev_xfrm TEXT; transformed_xml TEXT; xml_node TEXT; xml_node_list TEXT[]; raw_text TEXT; output_text TEXT := ''; BEGIN IF marc IS NULL OR marc = '' THEN RETURN NULL; END IF; -- Loop over the indexing entries FOR idx IN SELECT * FROM config.biblio_fingerprint ORDER BY format, id LOOP SELECT INTO xfrm * from config.xml_transform WHERE name = idx.format; -- See if we can skip the XSLT ... it's expensive IF prev_xfrm IS NULL OR prev_xfrm <> xfrm.name THEN -- Can't skip the transform IF xfrm.xslt <> '---' THEN transformed_xml := oils_xslt_process(marc,xfrm.xslt); ELSE transformed_xml := marc; END IF; prev_xfrm := xfrm.name; END IF; raw_text := COALESCE( naco_normalize( ARRAY_TO_STRING( oils_xpath( '//text()', (oils_xpath( idx.xpath, transformed_xml, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] ))[1] ), '' ) ), '' ); raw_text := REGEXP_REPLACE(raw_text, E'\\[.+?\\]', E''); raw_text := REGEXP_REPLACE(raw_text, E'\\mthe\\M|\\man?d?d\\M', E'', 'g'); -- arg! the pain! IF idx.first_word IS TRUE THEN raw_text := REGEXP_REPLACE(raw_text, E'^(\\w+).*?$', E'\\1'); END IF; output_text := output_text || idx.name || ':' || REGEXP_REPLACE(raw_text, E'\\s+', '', 'g') || ' '; END LOOP; RETURN BTRIM(output_text); END;
Function: biblio.extract_located_uris(editor_id bigint, marcxml text, bib_id integer)
Returns: void
Language: PLPGSQL
DECLARE uris TEXT[]; uri_xml TEXT; uri_label TEXT; uri_href TEXT; uri_use TEXT; uri_owner_list TEXT[]; uri_owner TEXT; uri_owner_id INT; uri_id INT; uri_cn_id INT; uri_map_id INT; current_uri INT; current_map INT; uri_map_count INT; current_uri_map_list INT[]; current_map_owner_list INT[]; BEGIN uris := oils_xpath('//*[@tag="856" and (@ind1="4" or @ind1="1") and (@ind2="0" or @ind2="1")]',marcxml); IF ARRAY_UPPER(uris,1) > 0 THEN FOR i IN 1 .. ARRAY_UPPER(uris, 1) LOOP -- First we pull info out of the 856 uri_xml := uris[i]; uri_href := (oils_xpath('//*[@code="u"]/text()',uri_xml))[1]; uri_label := (oils_xpath('//*[@code="y"]/text()|//*[@code="3"]/text()',uri_xml))[1]; uri_use := (oils_xpath('//*[@code="z"]/text()|//*[@code="2"]/text()|//*[@code="n"]/text()',uri_xml))[1]; IF uri_label IS NULL THEN uri_label := uri_href; END IF; CONTINUE WHEN uri_href IS NULL; -- Get the distinct list of libraries wanting to use SELECT ARRAY_AGG( DISTINCT REGEXP_REPLACE( x, $re$^.*?\((\w+)\).*$$re$, E'\\1' ) ) INTO uri_owner_list FROM UNNEST( oils_xpath( '//*[@code="9"]/text()|//*[@code="w"]/text()|//*[@code="n"]/text()', uri_xml ) )x; IF ARRAY_UPPER(uri_owner_list,1) > 0 THEN -- look for a matching uri IF uri_use IS NULL THEN SELECT id INTO uri_id FROM asset.uri WHERE label = uri_label AND href = uri_href AND use_restriction IS NULL AND active ORDER BY id LIMIT 1; IF NOT FOUND THEN -- create one INSERT INTO asset.uri (label, href, use_restriction) VALUES (uri_label, uri_href, uri_use); SELECT id INTO uri_id FROM asset.uri WHERE label = uri_label AND href = uri_href AND use_restriction IS NULL AND active; END IF; ELSE SELECT id INTO uri_id FROM asset.uri WHERE label = uri_label AND href = uri_href AND use_restriction = uri_use AND active ORDER BY id LIMIT 1; IF NOT FOUND THEN -- create one INSERT INTO asset.uri (label, href, use_restriction) VALUES (uri_label, uri_href, uri_use); SELECT id INTO uri_id FROM asset.uri WHERE label = uri_label AND href = uri_href AND use_restriction = uri_use AND active; END IF; END IF; FOR j IN 1 .. ARRAY_UPPER(uri_owner_list, 1) LOOP uri_owner := uri_owner_list[j]; SELECT id INTO uri_owner_id FROM actor.org_unit WHERE shortname = BTRIM(REPLACE(uri_owner,chr(160),'')); CONTINUE WHEN NOT FOUND; -- we need a call number to link through SELECT id INTO uri_cn_id FROM asset.call_number WHERE owning_lib = uri_owner_id AND record = bib_id AND label = '##URI##' AND NOT deleted; IF NOT FOUND THEN INSERT INTO asset.call_number (owning_lib, record, create_date, edit_date, creator, editor, label) VALUES (uri_owner_id, bib_id, 'now', 'now', editor_id, editor_id, '##URI##'); SELECT id INTO uri_cn_id FROM asset.call_number WHERE owning_lib = uri_owner_id AND record = bib_id AND label = '##URI##' AND NOT deleted; END IF; -- now, link them if they're not already SELECT id INTO uri_map_id FROM asset.uri_call_number_map WHERE call_number = uri_cn_id AND uri = uri_id; IF NOT FOUND THEN INSERT INTO asset.uri_call_number_map (call_number, uri) VALUES (uri_cn_id, uri_id); SELECT id INTO uri_map_id FROM asset.uri_call_number_map WHERE call_number = uri_cn_id AND uri = uri_id; END IF; current_uri_map_list := current_uri_map_list || uri_map_id; current_map_owner_list := current_map_owner_list || uri_cn_id; END LOOP; END IF; END LOOP; END IF; -- Clear any orphaned URIs, URI mappings and call -- numbers for this bib that weren't mapped above. FOR current_map IN SELECT m.id FROM asset.uri_call_number_map m LEFT JOIN asset.call_number cn ON (cn.id = m.call_number) WHERE cn.record = bib_id AND cn.label = '##URI##' AND (NOT (m.id = ANY (current_uri_map_list)) OR current_uri_map_list is NULL) LOOP SELECT uri INTO current_uri FROM asset.uri_call_number_map WHERE id = current_map; DELETE FROM asset.uri_call_number_map WHERE id = current_map; SELECT COUNT(*) INTO uri_map_count FROM asset.uri_call_number_map WHERE uri = current_uri; IF uri_map_count = 0 THEN DELETE FROM asset.uri WHERE id = current_uri; END IF; END LOOP; UPDATE asset.call_number SET deleted = TRUE, edit_date = now(), editor = editor_id WHERE id IN ( SELECT id FROM asset.call_number WHERE record = bib_id AND label = '##URI##' AND NOT deleted AND (NOT (id = ANY (current_map_owner_list)) OR current_map_owner_list is NULL) ); RETURN; END;
Function: biblio.extract_metabib_field_entry(only_fields bigint, field_types text, default_joiner text[], rid integer[])
Returns: SET OF field_entry_template
Language: PLPGSQL
DECLARE bib biblio.record_entry%ROWTYPE; idx config.metabib_field%ROWTYPE; xfrm config.xml_transform%ROWTYPE; prev_xfrm TEXT; transformed_xml TEXT; xml_node TEXT; xml_node_list TEXT[]; facet_text TEXT; display_text TEXT; browse_text TEXT; sort_value TEXT; raw_text TEXT; curr_text TEXT; joiner TEXT := default_joiner; -- XXX will index defs supply a joiner? authority_text TEXT; authority_link BIGINT; output_row metabib.field_entry_template%ROWTYPE; process_idx BOOL; BEGIN -- Start out with no field-use bools set output_row.browse_nocase = FALSE; output_row.browse_field = FALSE; output_row.facet_field = FALSE; output_row.display_field = FALSE; output_row.search_field = FALSE; -- Get the record SELECT INTO bib * FROM biblio.record_entry WHERE id = rid; -- Loop over the indexing entries FOR idx IN SELECT * FROM config.metabib_field WHERE id = ANY (only_fields) ORDER BY format LOOP CONTINUE WHEN idx.xpath IS NULL OR idx.xpath = ''; -- pure virtual field process_idx := FALSE; IF idx.display_field AND 'display' = ANY (field_types) THEN process_idx = TRUE; END IF; IF idx.browse_field AND 'browse' = ANY (field_types) THEN process_idx = TRUE; END IF; IF idx.search_field AND 'search' = ANY (field_types) THEN process_idx = TRUE; END IF; IF idx.facet_field AND 'facet' = ANY (field_types) THEN process_idx = TRUE; END IF; CONTINUE WHEN process_idx = FALSE; -- disabled for all types joiner := COALESCE(idx.joiner, default_joiner); SELECT INTO xfrm * from config.xml_transform WHERE name = idx.format; -- See if we can skip the XSLT ... it's expensive IF prev_xfrm IS NULL OR prev_xfrm <> xfrm.name THEN -- Can't skip the transform IF xfrm.xslt <> '---' THEN transformed_xml := oils_xslt_process(bib.marc,xfrm.xslt); ELSE transformed_xml := bib.marc; END IF; prev_xfrm := xfrm.name; END IF; xml_node_list := oils_xpath( idx.xpath, transformed_xml, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] ); raw_text := NULL; FOR xml_node IN SELECT x FROM unnest(xml_node_list) AS x LOOP CONTINUE WHEN xml_node !~ E'^\\s*<'; -- XXX much of this should be moved into oils_xpath_string... curr_text := ARRAY_TO_STRING(array_remove(array_remove( oils_xpath( '//text()', -- get the content of all the nodes within the main selected node REGEXP_REPLACE( xml_node, E'\\s+', ' ', 'g' ) -- Translate adjacent whitespace to a single space ), ' '), ''), -- throw away morally empty (bankrupt?) strings joiner ); CONTINUE WHEN curr_text IS NULL OR curr_text = ''; IF raw_text IS NOT NULL THEN raw_text := raw_text || joiner; END IF; raw_text := COALESCE(raw_text,'') || curr_text; -- autosuggest/metabib.browse_entry IF idx.browse_field THEN output_row.browse_nocase = idx.browse_nocase; IF idx.browse_xpath IS NOT NULL AND idx.browse_xpath <> '' THEN browse_text := oils_xpath_string( idx.browse_xpath, xml_node, joiner, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] ); ELSE browse_text := curr_text; END IF; IF idx.browse_sort_xpath IS NOT NULL AND idx.browse_sort_xpath <> '' THEN sort_value := oils_xpath_string( idx.browse_sort_xpath, xml_node, joiner, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] ); ELSE sort_value := browse_text; END IF; output_row.field_class = idx.field_class; output_row.field = idx.id; output_row.source = rid; output_row.value = BTRIM(REGEXP_REPLACE(browse_text, E'\\s+', ' ', 'g')); output_row.sort_value := public.naco_normalize(sort_value); output_row.authority := NULL; IF idx.authority_xpath IS NOT NULL AND idx.authority_xpath <> '' THEN authority_text := oils_xpath_string( idx.authority_xpath, xml_node, joiner, ARRAY[ ARRAY[xfrm.prefix, xfrm.namespace_uri], ARRAY['xlink','http://www.w3.org/1999/xlink'] ] ); IF authority_text ~ '^\d+$' THEN authority_link := authority_text::BIGINT; PERFORM * FROM authority.record_entry WHERE id = authority_link; IF FOUND THEN output_row.authority := authority_link; END IF; END IF; END IF; output_row.browse_field = TRUE; -- Returning browse rows with search_field = true for search+browse -- configs allows us to retain granularity of being able to search -- browse fields with "starts with" type operators (for example, for -- titles of songs in music albums) IF idx.search_field THEN output_row.search_field = TRUE; END IF; RETURN NEXT output_row; output_row.browse_nocase = FALSE; output_row.browse_field = FALSE; output_row.search_field = FALSE; output_row.sort_value := NULL; END IF; -- insert raw node text for faceting IF idx.facet_field THEN IF idx.facet_xpath IS NOT NULL AND idx.facet_xpath <> '' THEN facet_text := oils_xpath_string( idx.facet_xpath, xml_node, joiner, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] ); ELSE facet_text := curr_text; END IF; output_row.field_class = idx.field_class; output_row.field = -1 * idx.id; output_row.source = rid; output_row.value = BTRIM(REGEXP_REPLACE(facet_text, E'\\s+', ' ', 'g')); output_row.facet_field = TRUE; RETURN NEXT output_row; output_row.facet_field = FALSE; END IF; -- insert raw node text for display IF idx.display_field THEN IF idx.display_xpath IS NOT NULL AND idx.display_xpath <> '' THEN display_text := oils_xpath_string( idx.display_xpath, xml_node, joiner, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] ); ELSE display_text := curr_text; END IF; output_row.field_class = idx.field_class; output_row.field = -1 * idx.id; output_row.source = rid; output_row.value = BTRIM(REGEXP_REPLACE(display_text, E'\\s+', ' ', 'g')); output_row.display_field = TRUE; RETURN NEXT output_row; output_row.display_field = FALSE; END IF; END LOOP; CONTINUE WHEN raw_text IS NULL OR raw_text = ''; -- insert combined node text for searching IF idx.search_field THEN output_row.field_class = idx.field_class; output_row.field = idx.id; output_row.source = rid; output_row.value = BTRIM(REGEXP_REPLACE(raw_text, E'\\s+', ' ', 'g')); output_row.search_field = TRUE; RETURN NEXT output_row; output_row.search_field = FALSE; END IF; END LOOP; END;
Function: biblio.extract_quality(best_type text, best_lang text, marc text)
Returns: integer
Language: PLPGSQL
DECLARE qual INT; ldr TEXT; tval TEXT; tval_rec RECORD; bval TEXT; bval_rec RECORD; type_map RECORD; ff_pos RECORD; ff_tag_data TEXT; BEGIN IF marc IS NULL OR marc = '' THEN RETURN NULL; END IF; -- First, the count of tags qual := ARRAY_UPPER(oils_xpath('//*[local-name()="datafield"]', marc), 1); -- now go through a bunch of pain to get the record type IF best_type IS NOT NULL THEN ldr := (oils_xpath('//*[local-name()="leader"]/text()', marc))[1]; IF ldr IS NOT NULL THEN SELECT * INTO tval_rec FROM config.marc21_ff_pos_map WHERE fixed_field = 'Type' LIMIT 1; -- They're all the same SELECT * INTO bval_rec FROM config.marc21_ff_pos_map WHERE fixed_field = 'BLvl' LIMIT 1; -- They're all the same tval := SUBSTRING( ldr, tval_rec.start_pos + 1, tval_rec.length ); bval := SUBSTRING( ldr, bval_rec.start_pos + 1, bval_rec.length ); -- RAISE NOTICE 'type %, blvl %, ldr %', tval, bval, ldr; SELECT * INTO type_map FROM config.marc21_rec_type_map WHERE type_val LIKE '%' || tval || '%' AND blvl_val LIKE '%' || bval || '%'; IF type_map.code IS NOT NULL THEN IF best_type = type_map.code THEN qual := qual + qual / 2; END IF; FOR ff_pos IN SELECT * FROM config.marc21_ff_pos_map WHERE fixed_field = 'Lang' AND rec_type = type_map.code ORDER BY tag DESC LOOP ff_tag_data := SUBSTRING((oils_xpath('//*[@tag="' || ff_pos.tag || '"]/text()',marc))[1], ff_pos.start_pos + 1, ff_pos.length); IF ff_tag_data = best_lang THEN qual := qual + 100; END IF; END LOOP; END IF; END IF; END IF; -- Now look for some quality metrics -- DCL record? IF ARRAY_UPPER(oils_xpath('//*[@tag="040"]/*[@code="a" and contains(.,"DLC")]', marc), 1) = 1 THEN qual := qual + 10; END IF; -- From OCLC? IF (oils_xpath('//*[@tag="003"]/text()', marc))[1] ~* E'oclo?c' THEN qual := qual + 10; END IF; RETURN qual; END;
Function: biblio.fingerprint_trigger()
Returns: trigger
Language: PLPGSQL
BEGIN -- For TG_ARGV, first param is language (like 'eng'), second is record type (like 'BKS') IF NEW.deleted IS TRUE THEN -- we don't much care, then, do we? RETURN NEW; END IF; NEW.fingerprint := biblio.extract_fingerprint(NEW.marc); NEW.quality := biblio.extract_quality(NEW.marc, TG_ARGV[0], TG_ARGV[1]); RETURN NEW; END;
Function: biblio.flatten_marc(rid bigint)
Returns: SET OF full_rec
Language: PLPGSQL
DECLARE bib biblio.record_entry%ROWTYPE; output metabib.full_rec%ROWTYPE; field RECORD; BEGIN SELECT INTO bib * FROM biblio.record_entry WHERE id = rid; FOR field IN SELECT * FROM vandelay.flatten_marc( bib.marc ) LOOP output.record := rid; output.ind1 := field.ind1; output.ind2 := field.ind2; output.tag := field.tag; output.subfield := field.subfield; output.value := field.value; RETURN NEXT output; END LOOP; END;
Function: biblio.indexing_ingest_or_delete()
Returns: trigger
Language: PLPGSQL
DECLARE tmp_bool BOOL; BEGIN IF NEW.deleted THEN -- If this bib is deleted PERFORM * FROM config.internal_flag WHERE name = 'ingest.metarecord_mapping.preserve_on_delete' AND enabled; tmp_bool := FOUND; -- Just in case this is changed by some other statement PERFORM metabib.remap_metarecord_for_bib( NEW.id, NEW.fingerprint, TRUE, tmp_bool ); IF NOT tmp_bool THEN -- One needs to keep these around to support searches -- with the #deleted modifier, so one should turn on the named -- internal flag for that functionality. DELETE FROM metabib.record_attr_vector_list WHERE source = NEW.id; END IF; DELETE FROM authority.bib_linking WHERE bib = NEW.id; -- Avoid updating fields in bibs that are no longer visible DELETE FROM biblio.peer_bib_copy_map WHERE peer_record = NEW.id; -- Separate any multi-homed items DELETE FROM metabib.browse_entry_def_map WHERE source = NEW.id; -- Don't auto-suggest deleted bibs RETURN NEW; -- and we're done END IF; IF TG_OP = 'UPDATE' AND OLD.deleted IS FALSE THEN -- re-ingest? PERFORM * FROM config.internal_flag WHERE name = 'ingest.reingest.force_on_same_marc' AND enabled; IF NOT FOUND AND OLD.marc = NEW.marc THEN -- don't do anything if the MARC didn't change RETURN NEW; END IF; END IF; -- Record authority linking PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_authority_linking' AND enabled; IF NOT FOUND THEN PERFORM biblio.map_authority_linking( NEW.id, NEW.marc ); END IF; -- Flatten and insert the mfr data PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_metabib_full_rec' AND enabled; IF NOT FOUND THEN PERFORM metabib.reingest_metabib_full_rec(NEW.id); -- Now we pull out attribute data, which is dependent on the mfr for all but XPath-based fields PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_metabib_rec_descriptor' AND enabled; IF NOT FOUND THEN PERFORM metabib.reingest_record_attributes(NEW.id, NULL, NEW.marc, TG_OP = 'INSERT' OR OLD.deleted); END IF; END IF; -- Gather and insert the field entry data PERFORM metabib.reingest_metabib_field_entries(NEW.id); -- Located URI magic PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_located_uri' AND enabled; IF NOT FOUND THEN PERFORM biblio.extract_located_uris( NEW.id, NEW.marc, NEW.editor ); END IF; -- (re)map metarecord-bib linking IF TG_OP = 'INSERT' THEN -- if not deleted and performing an insert, check for the flag PERFORM * FROM config.internal_flag WHERE name = 'ingest.metarecord_mapping.skip_on_insert' AND enabled; IF NOT FOUND THEN PERFORM metabib.remap_metarecord_for_bib( NEW.id, NEW.fingerprint ); END IF; ELSE -- we're doing an update, and we're not deleted, remap PERFORM * FROM config.internal_flag WHERE name = 'ingest.metarecord_mapping.skip_on_update' AND enabled; IF NOT FOUND THEN PERFORM metabib.remap_metarecord_for_bib( NEW.id, NEW.fingerprint ); END IF; END IF; RETURN NEW; END;
Function: biblio.map_authority_linking(marc bigint, bibid text)
Returns: bigint
Language: SQL
DELETE FROM authority.bib_linking WHERE bib = $1; INSERT INTO authority.bib_linking (bib, authority) SELECT y.bib, y.authority FROM ( SELECT DISTINCT $1 AS bib, BTRIM(remove_paren_substring(txt))::BIGINT AS authority FROM unnest(oils_xpath('//*[@code="0"]/text()',$2)) x(txt) WHERE BTRIM(remove_paren_substring(txt)) ~ $re$^\d+$$re$ ) y JOIN authority.record_entry r ON r.id = y.authority; SELECT $1;
Function: biblio.marc21_extract_all_fixed_fields(rid bigint)
Returns: SET OF record_ff_map
Language: SQL
SELECT $1 AS record, ff_name, ff_value FROM vandelay.marc21_extract_all_fixed_fields( (SELECT marc FROM biblio.record_entry WHERE id = $1), TRUE );
Function: biblio.marc21_extract_fixed_field(ff bigint, rid text)
Returns: text
Language: SQL
SELECT * FROM vandelay.marc21_extract_fixed_field( (SELECT marc FROM biblio.record_entry WHERE id = $1), $2, TRUE );
Function: biblio.marc21_extract_fixed_field_list(ff bigint, rid text)
Returns: text[]
Language: SQL
SELECT * FROM vandelay.marc21_extract_fixed_field_list( (SELECT marc FROM biblio.record_entry WHERE id = $1), $2, TRUE );
Function: biblio.marc21_physical_characteristics(rid bigint)
Returns: SET OF marc21_physical_characteristics
Language: SQL
SELECT id, $1 AS record, ptype, subfield, value FROM vandelay.marc21_physical_characteristics( (SELECT marc FROM biblio.record_entry WHERE id = $1) );
Function: biblio.next_autogen_tcn_value()
Returns: text
Language: PLPGSQL
BEGIN RETURN 'AUTOGENERATED-' || nextval('biblio.autogen_tcn_value_seq'::TEXT); END;
Function: biblio.normalize_biblio_monograph_part_sortkey()
Returns: trigger
Language: PLPGSQL
BEGIN NEW.label_sortkey := REGEXP_REPLACE( evergreen.lpad_number_substrings( naco_normalize(NEW.label), '0', 10 ), E'\\s+', '', 'g' ); RETURN NEW; END;
Schema booking
Table: booking.reservation
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY DEFAULT nextval('money.billable_xact_id_seq'::regclass) | |
actor.usr.id | usr | integer | NOT NULL |
xact_start | timestamp with time zone | NOT NULL DEFAULT now() | |
xact_finish | timestamp with time zone | ||
unrecovered | boolean | ||
request_time | timestamp with time zone | NOT NULL DEFAULT now() | |
start_time | timestamp with time zone | ||
end_time | timestamp with time zone | ||
capture_time | timestamp with time zone | ||
cancel_time | timestamp with time zone | ||
pickup_time | timestamp with time zone | ||
return_time | timestamp with time zone | ||
booking_interval | interval | ||
fine_interval | interval | ||
fine_amount | numeric(8,2) | ||
max_fine | numeric(8,2) | ||
booking.resource_type.id | target_resource_type | integer | NOT NULL |
booking.resource.id | target_resource | integer | |
booking.resource.id | current_resource | integer | |
actor.org_unit.id | request_lib | integer | NOT NULL |
actor.org_unit.id | pickup_lib | integer | |
actor.usr.id | capture_staff | integer | |
email_notify | boolean | NOT NULL DEFAULT false | |
note | text |
Table booking.reservation Inherits billable_xact,
Tables referencing this one via Foreign Key Constraints:
Table: booking.reservation_attr_value_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
booking.reservation.id | reservation | integer | UNIQUE#1 NOT NULL |
booking.resource_attr_value.id | attr_value | integer | UNIQUE#1 NOT NULL |
Table: booking.resource
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | owner | integer | UNIQUE#1 NOT NULL |
booking.resource_type.id | type | integer | NOT NULL |
overbook | boolean | NOT NULL DEFAULT false | |
barcode | text | UNIQUE#1 NOT NULL | |
deposit | boolean | NOT NULL DEFAULT false | |
deposit_amount | numeric(8,2) | NOT NULL DEFAULT 0.00 | |
user_fee | numeric(8,2) | NOT NULL DEFAULT 0.00 |
Tables referencing this one via Foreign Key Constraints:
Table: booking.resource_attr
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | owner | integer | NOT NULL |
name | text | UNIQUE#1 NOT NULL | |
booking.resource_type.id | resource_type | integer | UNIQUE#1 NOT NULL |
required | boolean | NOT NULL DEFAULT false |
Tables referencing this one via Foreign Key Constraints:
Table: booking.resource_attr_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
booking.resource.id | resource | integer | UNIQUE#1 NOT NULL |
booking.resource_attr.id | resource_attr | integer | UNIQUE#1 NOT NULL |
booking.resource_attr_value.id | value | integer | NOT NULL |
Table: booking.resource_attr_value
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | owner | integer | UNIQUE#1 NOT NULL |
booking.resource_attr.id | attr | integer | UNIQUE#1 NOT NULL |
valid_value | text | UNIQUE#1 NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: booking.resource_type
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE#1 NOT NULL | |
elbow_room | interval | ||
fine_interval | interval | ||
fine_amount | numeric(8,2) | NOT NULL | |
max_fine | numeric(8,2) | ||
actor.org_unit.id | owner | integer | UNIQUE#1 NOT NULL |
catalog_item | boolean | NOT NULL DEFAULT false | |
transferable | boolean | NOT NULL DEFAULT false | |
biblio.record_entry.id | record | bigint | UNIQUE#1 |
Tables referencing this one via Foreign Key Constraints:
Schema config
The config schema holds static configuration data for the Evergreen installation.
View: config.audience_map
F-Key | Name | Type | Description |
---|---|---|---|
code | text | ||
value | text | ||
description | text |
SELECT coded_value_map.code , coded_value_map.value , coded_value_map.description FROM config.coded_value_map WHERE (coded_value_map.ctype = 'audience'::text);
Table: config.barcode_completion
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
active | boolean | NOT NULL DEFAULT true | |
actor.org_unit.id | org_unit | integer | NOT NULL |
prefix | text | ||
suffix | text | ||
length | integer | NOT NULL | |
padding | text | ||
padding_end | boolean | NOT NULL DEFAULT false | |
asset | boolean | NOT NULL DEFAULT true | |
actor | boolean | NOT NULL DEFAULT true |
Table: config.best_hold_order
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE | |
pprox | integer | ||
hprox | integer | ||
owning_lib_to_home_lib_prox | integer | ||
aprox | integer | ||
approx | integer | ||
priority | integer | ||
cut | integer | ||
depth | integer | ||
htime | integer | ||
rtime | integer | ||
shtime | integer |
Name | Constraint |
---|---|
best_hold_order_check | CHECK (((pprox IS NOT NULL) OR (hprox IS NOT NULL) OR (owning_lib_to_home_lib_prox IS NOT NULL) OR (aprox IS NOT NULL) OR (priority IS NOT NULL) OR (cut IS NOT NULL) OR (depth IS NOT NULL) OR (htime IS NOT NULL) OR (rtime IS NOT NULL))) |
View: config.bib_level_map
F-Key | Name | Type | Description |
---|---|---|---|
code | text | ||
value | text |
SELECT coded_value_map.code , coded_value_map.value FROM config.coded_value_map WHERE (coded_value_map.ctype = 'bib_level'::text);
Table: config.bib_source
This is table is used to set up the relative "quality" of each MARC source, such as OCLC. Also identifies "transcendant" sources, i.e., sources of bib records that should display in the OPAC even if no copies or located URIs are attached. Also indicates if the source is allowed to have actual copies on its bibs. Volumes for targeted URIs are unaffected by this setting.
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
quality | integer | ||
source | text | UNIQUE NOT NULL | |
transcendant | boolean | NOT NULL DEFAULT false | |
can_have_copies | boolean | NOT NULL DEFAULT true |
Name | Constraint |
---|---|
bib_source_quality_check | CHECK (((quality >= 0) AND (quality <= 100))) |
Tables referencing this one via Foreign Key Constraints:
Table: config.biblio_fingerprint
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | NOT NULL | |
xpath | text | NOT NULL | |
first_word | boolean | NOT NULL DEFAULT false | |
format | text | NOT NULL DEFAULT 'marcxml'::text |
Table: config.billing_type
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE#1 NOT NULL | |
actor.org_unit.id | owner | integer | UNIQUE#1 NOT NULL |
default_price | numeric(6,2) |
Tables referencing this one via Foreign Key Constraints:
Table: config.carousel_type
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | NOT NULL | |
automatic | boolean | NOT NULL DEFAULT true | |
filter_by_age | boolean | NOT NULL DEFAULT false | |
filter_by_copy_owning_lib | boolean | NOT NULL DEFAULT false | |
filter_by_copy_location | boolean | NOT NULL DEFAULT false |
Tables referencing this one via Foreign Key Constraints:
Table: config.circ_limit_group
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE NOT NULL | |
description | text |
Tables referencing this one via Foreign Key Constraints:
Table: config.circ_limit_set
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE NOT NULL | |
actor.org_unit.id | owning_lib | integer | NOT NULL |
items_out | integer | NOT NULL | |
depth | integer | NOT NULL | |
global | boolean | NOT NULL DEFAULT false | |
description | text |
Tables referencing this one via Foreign Key Constraints:
Table: config.circ_limit_set_circ_mod_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
config.circ_limit_set.id | limit_set | integer | UNIQUE#1 NOT NULL |
config.circ_modifier.code | circ_mod | text | UNIQUE#1 NOT NULL |
Table: config.circ_limit_set_copy_loc_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
config.circ_limit_set.id | limit_set | integer | UNIQUE#1 NOT NULL |
asset.copy_location.id | copy_loc | integer | UNIQUE#1 NOT NULL |
Table: config.circ_limit_set_group_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
config.circ_limit_set.id | limit_set | integer | UNIQUE#1 NOT NULL |
config.circ_limit_group.id | limit_group | integer | UNIQUE#1 NOT NULL |
check_only | boolean | NOT NULL DEFAULT false |
Table: config.circ_matrix_limit_set_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
config.circ_matrix_matchpoint.id | matchpoint | integer | UNIQUE#1 NOT NULL |
config.circ_limit_set.id | limit_set | integer | UNIQUE#1 NOT NULL |
fallthrough | boolean | NOT NULL DEFAULT false | |
active | boolean | NOT NULL DEFAULT true |
Table: config.circ_matrix_matchpoint
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
active | boolean | NOT NULL DEFAULT true | |
actor.org_unit.id | org_unit | integer | NOT NULL |
permission.grp_tree.id | grp | integer | NOT NULL |
config.circ_modifier.code | circ_modifier | text | |
asset.copy_location.id | copy_location | integer | |
marc_type | text | ||
marc_form | text | ||
marc_bib_level | text | ||
marc_vr_format | text | ||
actor.org_unit.id | copy_circ_lib | integer | |
actor.org_unit.id | copy_owning_lib | integer | |
actor.org_unit.id | user_home_ou | integer | |
ref_flag | boolean | ||
juvenile_flag | boolean | ||
is_renewal | boolean | ||
usr_age_lower_bound | interval | ||
usr_age_upper_bound | interval | ||
item_age | interval | ||
circulate | boolean | ||
config.rule_circ_duration.id | duration_rule | integer | |
config.rule_recurring_fine.id | recurring_fine_rule | integer | |
config.rule_max_fine.id | max_fine_rule | integer | |
config.hard_due_date.id | hard_due_date | integer | |
renewals | integer | ||
grace_period | interval | ||
script_test | text | ||
total_copy_hold_ratio | double precision | ||
available_copy_hold_ratio | double precision | ||
description | text | ||
renew_extends_due_date | boolean | NOT NULL DEFAULT false | |
renew_extend_min_interval | interval |
Tables referencing this one via Foreign Key Constraints:
Table: config.circ_matrix_weights
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE NOT NULL | |
org_unit | numeric(6,2) | NOT NULL | |
grp | numeric(6,2) | NOT NULL | |
circ_modifier | numeric(6,2) | NOT NULL | |
copy_location | numeric(6,2) | NOT NULL | |
marc_type | numeric(6,2) | NOT NULL | |
marc_form | numeric(6,2) | NOT NULL | |
marc_bib_level | numeric(6,2) | NOT NULL | |
marc_vr_format | numeric(6,2) | NOT NULL | |
copy_circ_lib | numeric(6,2) | NOT NULL | |
copy_owning_lib | numeric(6,2) | NOT NULL | |
user_home_ou | numeric(6,2) | NOT NULL | |
ref_flag | numeric(6,2) | NOT NULL | |
juvenile_flag | numeric(6,2) | NOT NULL | |
is_renewal | numeric(6,2) | NOT NULL | |
usr_age_lower_bound | numeric(6,2) | NOT NULL | |
usr_age_upper_bound | numeric(6,2) | NOT NULL | |
item_age | numeric(6,2) | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: config.circ_modifier
F-Key | Name | Type | Description |
---|---|---|---|
code | text | PRIMARY KEY | |
name | text | UNIQUE NOT NULL | |
description | text | NOT NULL | |
sip2_media_type | text | NOT NULL | |
magnetic_media | boolean | NOT NULL DEFAULT true | |
avg_wait_time | interval |
Tables referencing this one via Foreign Key Constraints:
Table: config.coded_value_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
config.record_attr_definition.name | ctype | text | NOT NULL |
code | text | NOT NULL | |
value | text | NOT NULL | |
description | text | ||
opac_visible | boolean | NOT NULL DEFAULT true | |
search_label | text | ||
is_simple | boolean | NOT NULL DEFAULT false | |
concept_uri | text |
Tables referencing this one via Foreign Key Constraints:
config_coded_value_map_ctype_idx ctypeTable: config.composite_attr_entry_definition
F-Key | Name | Type | Description |
---|---|---|---|
config.coded_value_map.id | coded_value | integer | PRIMARY KEY |
definition | text | NOT NULL |
Table: config.copy_alert_type
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | scope_org | integer | NOT NULL |
active | boolean | NOT NULL DEFAULT true | |
name | text | UNIQUE NOT NULL | |
state | config.copy_alert_type_state | ||
event | config.copy_alert_type_event | ||
in_renew | boolean | ||
invert_location | boolean | NOT NULL DEFAULT false | |
at_circ | boolean | ||
at_owning | boolean | ||
next_status | integer[] |
Tables referencing this one via Foreign Key Constraints:
Table: config.copy_status
Copy Statuses The available copy statuses, and whether a copy in that status is available for hold request capture. 0 (zero) is the only special number in this set, meaning that the item is available for immediate checkout, and is counted as available in the OPAC. Statuses with an ID below 100 are not removable, and have special meaning in the code. Do not change them except to translate the textual name. You may add and remove statuses above 100, and these can be used to remove items from normal circulation without affecting the rest of the copy's values or its location.
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE NOT NULL | |
holdable | boolean | NOT NULL DEFAULT false | |
opac_visible | boolean | NOT NULL DEFAULT false | |
copy_active | boolean | NOT NULL DEFAULT false | |
restrict_copy_delete | boolean | NOT NULL DEFAULT false | |
is_available | boolean | NOT NULL DEFAULT false | |
hopeless_prone | boolean | NOT NULL DEFAULT false |
Tables referencing this one via Foreign Key Constraints:
Table: config.copy_tag_type
F-Key | Name | Type | Description |
---|---|---|---|
code | text | PRIMARY KEY | |
label | text | NOT NULL | |
actor.org_unit.id | owner | integer | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
config_copy_tag_type_owner_idx ownerTable: config.db_patch_dependencies
F-Key | Name | Type | Description |
---|---|---|---|
db_patch | text | PRIMARY KEY | |
supersedes | text[] | ||
deprecates | text[] |
Table: config.display_field_map
F-Key | Name | Type | Description |
---|---|---|---|
name | text | PRIMARY KEY | |
config.metabib_field.id | field | integer | |
multi | boolean | DEFAULT false |
Table: config.filter_dialog_filter_set
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE#1 NOT NULL | |
actor.org_unit.id | owning_lib | integer | UNIQUE#1 NOT NULL |
actor.usr.id | creator | integer | NOT NULL |
create_time | timestamp with time zone | NOT NULL DEFAULT now() | |
config.filter_dialog_interface.key | interface | text | NOT NULL |
filters | text | NOT NULL |
Name | Constraint |
---|---|
config_filter_dialog_filter_set_filters_check | CHECK (is_json(filters)) |
Table: config.filter_dialog_interface
F-Key | Name | Type | Description |
---|---|---|---|
key | text | PRIMARY KEY | |
description | text |
Tables referencing this one via Foreign Key Constraints:
Table: config.floating_group
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE NOT NULL | |
manual | boolean | NOT NULL DEFAULT false |
Tables referencing this one via Foreign Key Constraints:
Table: config.floating_group_member
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
config.floating_group.id | floating_group | integer | NOT NULL |
actor.org_unit.id | org_unit | integer | NOT NULL |
stop_depth | integer | NOT NULL | |
max_depth | integer | ||
exclude | boolean | NOT NULL DEFAULT false |
Table: config.geolocation_service
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
active | boolean | ||
actor.org_unit.id | owner | integer | NOT NULL |
name | text | ||
service_code | text | ||
api_key | text |
Table: config.global_flag
F-Key | Name | Type | Description |
---|---|---|---|
name | text | PRIMARY KEY | |
value | text | ||
enabled | boolean | NOT NULL DEFAULT false | |
label | text | NOT NULL |
Table config.global_flag Inherits internal_flag,
Table: config.hard_due_date
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE NOT NULL | |
ceiling_date | timestamp with time zone | NOT NULL | |
forceto | boolean | NOT NULL | |
owner | integer | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: config.hard_due_date_values
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
config.hard_due_date.id | hard_due_date | integer | NOT NULL |
ceiling_date | timestamp with time zone | NOT NULL | |
active_date | timestamp with time zone | NOT NULL |
Table: config.hold_matrix_matchpoint
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
active | boolean | NOT NULL DEFAULT true | |
strict_ou_match | boolean | NOT NULL DEFAULT false | |
actor.org_unit.id | user_home_ou | integer | |
actor.org_unit.id | request_ou | integer | |
actor.org_unit.id | pickup_ou | integer | |
actor.org_unit.id | item_owning_ou | integer | |
actor.org_unit.id | item_circ_ou | integer | |
permission.grp_tree.id | usr_grp | integer | |
permission.grp_tree.id | requestor_grp | integer | NOT NULL |
config.circ_modifier.code | circ_modifier | text | |
marc_type | text | ||
marc_form | text | ||
marc_bib_level | text | ||
marc_vr_format | text | ||
juvenile_flag | boolean | ||
ref_flag | boolean | ||
item_age | interval | ||
holdable | boolean | NOT NULL DEFAULT true | |
distance_is_from_owner | boolean | NOT NULL DEFAULT false | |
actor.org_unit_type.id | transit_range | integer | |
max_holds | integer | ||
include_frozen_holds | boolean | NOT NULL DEFAULT true | |
stop_blocked_user | boolean | NOT NULL DEFAULT false | |
config.rule_age_hold_protect.id | age_hold_protect_rule | integer | |
description | text |
Table: config.hold_matrix_weights
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE NOT NULL | |
user_home_ou | numeric(6,2) | NOT NULL | |
request_ou | numeric(6,2) | NOT NULL | |
pickup_ou | numeric(6,2) | NOT NULL | |
item_owning_ou | numeric(6,2) | NOT NULL | |
item_circ_ou | numeric(6,2) | NOT NULL | |
usr_grp | numeric(6,2) | NOT NULL | |
requestor_grp | numeric(6,2) | NOT NULL | |
circ_modifier | numeric(6,2) | NOT NULL | |
marc_type | numeric(6,2) | NOT NULL | |
marc_form | numeric(6,2) | NOT NULL | |
marc_bib_level | numeric(6,2) | NOT NULL | |
marc_vr_format | numeric(6,2) | NOT NULL | |
juvenile_flag | numeric(6,2) | NOT NULL | |
ref_flag | numeric(6,2) | NOT NULL | |
item_age | numeric(6,2) | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: config.hold_type
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | NOT NULL | |
hold_type | text | UNIQUE | |
description | text |
Tables referencing this one via Foreign Key Constraints:
Table: config.i18n_core
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
fq_field | text | NOT NULL | |
identity_value | text | NOT NULL | |
config.i18n_locale.code | translation | text | NOT NULL |
string | text | NOT NULL |
Table: config.i18n_locale
F-Key | Name | Type | Description |
---|---|---|---|
code | text | PRIMARY KEY | |
marc_code | text | NOT NULL | |
name | text | UNIQUE NOT NULL | |
description | text | ||
rtl | boolean | NOT NULL DEFAULT false |
Tables referencing this one via Foreign Key Constraints:
Table: config.identification_type
Types of valid patron identification. Each patron must display at least one valid form of identification in order to get a library card. This table lists those forms.
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: config.idl_field_doc
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
fm_class | text | NOT NULL | |
field | text | NOT NULL | |
actor.org_unit.id | owner | integer | NOT NULL |
string | text | NOT NULL |
Table: config.index_normalizer
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE NOT NULL | |
description | text | ||
func | text | NOT NULL | |
param_count | integer | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: config.internal_flag
F-Key | Name | Type | Description |
---|---|---|---|
name | text | PRIMARY KEY | |
value | text | ||
enabled | boolean | NOT NULL DEFAULT false |
View: config.item_form_map
F-Key | Name | Type | Description |
---|---|---|---|
code | text | ||
value | text |
SELECT coded_value_map.code , coded_value_map.value FROM config.coded_value_map WHERE (coded_value_map.ctype = 'item_form'::text);
View: config.item_type_map
F-Key | Name | Type | Description |
---|---|---|---|
code | text | ||
value | text |
SELECT coded_value_map.code , coded_value_map.value FROM config.coded_value_map WHERE (coded_value_map.ctype = 'item_type'::text);
View: config.language_map
F-Key | Name | Type | Description |
---|---|---|---|
code | text | ||
value | text |
SELECT coded_value_map.code , coded_value_map.value FROM config.coded_value_map WHERE (coded_value_map.ctype = 'item_lang'::text);
View: config.lit_form_map
F-Key | Name | Type | Description |
---|---|---|---|
code | text | ||
value | text | ||
description | text |
SELECT coded_value_map.code , coded_value_map.value , coded_value_map.description FROM config.coded_value_map WHERE (coded_value_map.ctype = 'lit_form'::text);
Table: config.marc21_ff_pos_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
fixed_field | text | NOT NULL | |
tag | text | NOT NULL | |
rec_type | text | NOT NULL | |
start_pos | integer | NOT NULL | |
length | integer | NOT NULL | |
default_val | text | NOT NULL DEFAULT ' '::text |
Table: config.marc21_physical_characteristic_subfield_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
config.marc21_physical_characteristic_type_map.ptype_key | ptype_key | text | NOT NULL |
subfield | text | NOT NULL | |
start_pos | integer | NOT NULL | |
length | integer | NOT NULL | |
label | text | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: config.marc21_physical_characteristic_type_map
F-Key | Name | Type | Description |
---|---|---|---|
ptype_key | text | PRIMARY KEY | |
label | text | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: config.marc21_physical_characteristic_value_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
value | text | NOT NULL | |
config.marc21_physical_characteristic_subfield_map.id | ptype_subfield | integer | NOT NULL |
label | text | NOT NULL |
Table: config.marc21_rec_type_map
F-Key | Name | Type | Description |
---|---|---|---|
code | text | PRIMARY KEY | |
type_val | text | NOT NULL | |
blvl_val | text | NOT NULL |
Table: config.marc_field
This table stores a list of MARC fields recognized by the Evergreen instance. Note that we're not aiming for completely generic ISO2709 support: we're assuming things like three characters for a tag, one-character subfield labels, two indicators per variable data field, and the like, all of which are technically specializations of ISO2709. Of particular significance is the owner column; if it's set to a null value, the field definition is assumed to come from a national standards body; if it's set to a non-null value, the field definition is an OU-level addition to or override of the standard.
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
config.marc_format.id | marc_format | integer | NOT NULL |
marc_record_type | config.marc_record_type | NOT NULL | |
tag | character(3) | NOT NULL | |
name | text | ||
description | text | ||
fixed_field | boolean | ||
repeatable | boolean | ||
mandatory | boolean | ||
hidden | boolean | ||
actor.org_unit.id | owner | integer |
Name | Constraint |
---|---|
config_standard_marc_tags_are_fully_specified | CHECK (((owner IS NOT NULL) OR ((owner IS NULL) AND (repeatable IS NOT NULL) AND (mandatory IS NOT NULL) AND (hidden IS NOT NULL)))) |
View: config.marc_field_for_ou
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
marc_format | integer | ||
marc_record_type | config.marc_record_type | ||
tag | character(3) | ||
name | text | ||
description | text | ||
fixed_field | boolean | ||
repeatable | boolean | ||
mandatory | boolean | ||
hidden | boolean | ||
owner | integer | ||
depth | integer |
WITH RECURSIVE ou_marc_fields (id , marc_format , marc_record_type , tag , name , description , fixed_field , repeatable , mandatory , hidden , owner , depth ) AS ( SELECT marc_field.id , marc_field.marc_format , marc_field.marc_record_type , marc_field.tag , marc_field.name , marc_field.description , marc_field.fixed_field , marc_field.repeatable , marc_field.mandatory , marc_field.hidden , marc_field.owner , 0 AS "?column?" FROM config.marc_field WHERE (marc_field.owner IS NULL) UNION SELECT marc_field.id , marc_field.marc_format , marc_field.marc_record_type , marc_field.tag , marc_field.name , marc_field.description , marc_field.fixed_field , marc_field.repeatable , marc_field.mandatory , marc_field.hidden , marc_field.owner , 0 FROM config.marc_field WHERE (NOT (ARRAY[ (marc_field.marc_format)::text , (marc_field.marc_record_type)::text , (marc_field.tag)::text] IN ( SELECT ARRAY[ (marc_field_1.marc_format)::text , (marc_field_1.marc_record_type)::text , (marc_field_1.tag)::text] AS "array" FROM config.marc_field marc_field_1 WHERE (marc_field_1.owner IS NULL) ) ) ) UNION SELECT c.id , c.marc_format , c.marc_record_type , c.tag , COALESCE (c.name , p.name ) AS "coalesce" , COALESCE (c.description , p.description ) AS "coalesce" , COALESCE (c.fixed_field , p.fixed_field ) AS "coalesce" , COALESCE (c.repeatable , p.repeatable ) AS "coalesce" , COALESCE (c.mandatory , p.mandatory ) AS "coalesce" , COALESCE (c.hidden , p.hidden ) AS "coalesce" , c.owner , (p.depth + 1) FROM ( (config.marc_field c JOIN ou_marc_fields p USING (marc_format , marc_record_type , tag ) ) JOIN actor.org_unit aou ON ( (c.owner = aou.id) ) ) WHERE ( (aou.parent_ou = p.owner) OR ( (aou.parent_ou IS NULL) AND (p.owner IS NULL) ) ) ) SELECT ou_marc_fields.id , ou_marc_fields.marc_format , ou_marc_fields.marc_record_type , ou_marc_fields.tag , ou_marc_fields.name , ou_marc_fields.description , ou_marc_fields.fixed_field , ou_marc_fields.repeatable , ou_marc_fields.mandatory , ou_marc_fields.hidden , ou_marc_fields.owner , ou_marc_fields.depth FROM ou_marc_fields;
Table: config.marc_format
List of MARC formats supported by this Evergreen database. This exists primarily as a hook for future support of UNIMARC, though whether that will ever happen remains to be seen.
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
code | text | NOT NULL | |
name | text | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: config.marc_subfield
This table stores the list of subfields recognized by this Evergreen instance. As with config.marc_field, of particular significance is the owner column; if it's set to a null value, the subfield definition is assumed to come from a national standards body; if it's set to a non-null value, the subfield definition is an OU-level addition to or override of the standard.
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
config.marc_format.id | marc_format | integer | NOT NULL |
marc_record_type | config.marc_record_type | NOT NULL | |
tag | character(3) | NOT NULL | |
code | character(1) | NOT NULL | |
description | text | ||
repeatable | boolean | ||
mandatory | boolean | ||
hidden | boolean | ||
config.record_attr_definition.name | value_ctype | text | |
actor.org_unit.id | owner | integer |
Name | Constraint |
---|---|
config_standard_marc_subfields_are_fully_specified | CHECK (((owner IS NOT NULL) OR ((owner IS NULL) AND (repeatable IS NOT NULL) AND (mandatory IS NOT NULL) AND (hidden IS NOT NULL)))) |
View: config.marc_subfield_for_ou
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
marc_format | integer | ||
marc_record_type | config.marc_record_type | ||
tag | character(3) | ||
code | character(1) | ||
description | text | ||
repeatable | boolean | ||
mandatory | boolean | ||
hidden | boolean | ||
value_ctype | text | ||
owner | integer | ||
depth | integer |
WITH RECURSIVE ou_marc_subfields (id , marc_format , marc_record_type , tag , code , description , repeatable , mandatory , hidden , value_ctype , owner , depth ) AS ( SELECT marc_subfield.id , marc_subfield.marc_format , marc_subfield.marc_record_type , marc_subfield.tag , marc_subfield.code , marc_subfield.description , marc_subfield.repeatable , marc_subfield.mandatory , marc_subfield.hidden , marc_subfield.value_ctype , marc_subfield.owner , 0 AS "?column?" FROM config.marc_subfield WHERE (marc_subfield.owner IS NULL) UNION SELECT marc_subfield.id , marc_subfield.marc_format , marc_subfield.marc_record_type , marc_subfield.tag , marc_subfield.code , marc_subfield.description , marc_subfield.repeatable , marc_subfield.mandatory , marc_subfield.hidden , marc_subfield.value_ctype , marc_subfield.owner , 0 FROM config.marc_subfield WHERE (NOT (ARRAY[ (marc_subfield.marc_format)::text , (marc_subfield.marc_record_type)::text , (marc_subfield.tag)::text , (marc_subfield.code)::text] IN ( SELECT ARRAY[ (marc_subfield_1.marc_format)::text , (marc_subfield_1.marc_record_type)::text , (marc_subfield_1.tag)::text , (marc_subfield_1.code)::text] AS "array" FROM config.marc_subfield marc_subfield_1 WHERE (marc_subfield_1.owner IS NULL) ) ) ) UNION SELECT c.id , c.marc_format , c.marc_record_type , c.tag , c.code , COALESCE (c.description , p.description ) AS "coalesce" , COALESCE (c.repeatable , p.repeatable ) AS "coalesce" , COALESCE (c.mandatory , p.mandatory ) AS "coalesce" , COALESCE (c.hidden , p.hidden ) AS "coalesce" , COALESCE (c.value_ctype , p.value_ctype ) AS "coalesce" , c.owner , (p.depth + 1) FROM ( (config.marc_subfield c JOIN ou_marc_subfields p USING (marc_format , marc_record_type , tag , code ) ) JOIN actor.org_unit aou ON ( (c.owner = aou.id) ) ) WHERE ( (aou.parent_ou = p.owner) OR ( (aou.parent_ou IS NULL) AND (p.owner IS NULL) ) ) ) SELECT ou_marc_subfields.id , ou_marc_subfields.marc_format , ou_marc_subfields.marc_record_type , ou_marc_subfields.tag , ou_marc_subfields.code , ou_marc_subfields.description , ou_marc_subfields.repeatable , ou_marc_subfields.mandatory , ou_marc_subfields.hidden , ou_marc_subfields.value_ctype , ou_marc_subfields.owner , ou_marc_subfields.depth FROM ou_marc_subfields;
Table: config.metabib_class
F-Key | Name | Type | Description |
---|---|---|---|
name | text | PRIMARY KEY | |
label | text | UNIQUE NOT NULL | |
buoyant | boolean | NOT NULL DEFAULT false | |
restrict | boolean | NOT NULL DEFAULT false | |
combined | boolean | NOT NULL DEFAULT false | |
a_weight | numeric | NOT NULL DEFAULT 1.0 | |
b_weight | numeric | NOT NULL DEFAULT 0.4 | |
c_weight | numeric | NOT NULL DEFAULT 0.2 | |
d_weight | numeric | NOT NULL DEFAULT 0.1 |
Tables referencing this one via Foreign Key Constraints:
Table: config.metabib_class_ts_map
Text Search Configs for metabib class indexing This table contains text search config definitions for storing index_vector values.
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
config.metabib_class.name | field_class | text | NOT NULL |
config.ts_config_list.id | ts_config | text | NOT NULL |
active | boolean | NOT NULL DEFAULT true | |
index_weight | character(1) | NOT NULL DEFAULT 'C'::bpchar | |
index_lang | text | ||
search_lang | text | ||
always | boolean | NOT NULL DEFAULT true |
Name | Constraint |
---|---|
metabib_class_ts_map_index_weight_check | CHECK ((index_weight = ANY (ARRAY['A'::bpchar, 'B'::bpchar, 'C'::bpchar, 'D'::bpchar]))) |
Table: config.metabib_field
XPath used for record indexing ingest This table contains the XPath used to chop up MODS into its indexable parts. Each XPath entry is named and assigned to a "class" of either title, subject, author, keyword, series or identifier.
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
config.metabib_class.name | field_class | text | NOT NULL |
name | text | NOT NULL | |
label | text | NOT NULL | |
xpath | text | ||
weight | integer | NOT NULL DEFAULT 1 | |
config.xml_transform.name | format | text | NOT NULL DEFAULT 'mods33'::text |
search_field | boolean | NOT NULL DEFAULT true | |
facet_field | boolean | NOT NULL DEFAULT false | |
browse_field | boolean | NOT NULL DEFAULT true | |
browse_nocase | boolean | NOT NULL DEFAULT false | |
browse_xpath | text | ||
browse_sort_xpath | text | ||
facet_xpath | text | ||
display_xpath | text | ||
authority_xpath | text | ||
joiner | text | ||
restrict | boolean | NOT NULL DEFAULT false | |
display_field | boolean | NOT NULL DEFAULT true |
Tables referencing this one via Foreign Key Constraints:
Table: config.metabib_field_index_norm_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
config.metabib_field.id | field | integer | NOT NULL |
config.index_normalizer.id | norm | integer | NOT NULL |
params | text | ||
pos | integer | NOT NULL |
Table: config.metabib_field_ts_map
Text Search Configs for metabib field indexing This table contains text search config definitions for storing index_vector values.
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
config.metabib_field.id | metabib_field | integer | NOT NULL |
config.ts_config_list.id | ts_config | text | NOT NULL |
active | boolean | NOT NULL DEFAULT true | |
index_weight | character(1) | NOT NULL DEFAULT 'C'::bpchar | |
index_lang | text | ||
search_lang | text |
Name | Constraint |
---|---|
metabib_field_ts_map_index_weight_check | CHECK ((index_weight = ANY (ARRAY['A'::bpchar, 'B'::bpchar, 'C'::bpchar, 'D'::bpchar]))) |
Table: config.metabib_field_virtual_map
Maps between real (physically extracted) index definitions and virtual (target sync, no required extraction of its own) index definitions. The virtual side may not extract any data of its own, but will collect data from all of the real fields. This reduces extraction (ingest) overhead by eliminating duplcated extraction, and allows for searching across novel combinations of fields, such as names used as either subjects or authors. By preserving this mapping rather than defining duplicate extractions, information about the originating, "real" index definitions can be used in interesting ways, such as highlighting in search results.
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
config.metabib_field.id | real | integer | NOT NULL |
config.metabib_field.id | virtual | integer | NOT NULL |
weight | integer | NOT NULL DEFAULT 1 |
Table: config.metabib_search_alias
F-Key | Name | Type | Description |
---|---|---|---|
alias | text | PRIMARY KEY | |
config.metabib_class.name | field_class | text | NOT NULL |
config.metabib_field.id | field | integer |
Table: config.net_access_level
Patron Network Access level This will be used to inform the in-library firewall of how much internet access the using patron should be allowed.
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: config.non_cataloged_type
Types of valid non-cataloged items.
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
owning_lib | integer | UNIQUE#1 NOT NULL | |
name | text | UNIQUE#1 NOT NULL | |
circ_duration | interval | NOT NULL DEFAULT '14 days'::interval | |
in_house | boolean | NOT NULL DEFAULT false |
Tables referencing this one via Foreign Key Constraints:
Table: config.openathens_identity
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
active | boolean | NOT NULL DEFAULT true | |
actor.org_unit.id | org_unit | integer | NOT NULL |
api_key | text | NOT NULL | |
connection_id | text | NOT NULL | |
connection_uri | text | NOT NULL | |
auto_signon_enabled | boolean | NOT NULL DEFAULT true | |
auto_signout_enabled | boolean | NOT NULL DEFAULT false | |
config.openathens_uid_field.id | unique_identifier | integer | NOT NULL DEFAULT 1 |
config.openathens_name_field.id | display_name | integer | NOT NULL DEFAULT 1 |
release_prefix | boolean | NOT NULL DEFAULT false | |
release_first_given_name | boolean | NOT NULL DEFAULT false | |
release_second_given_name | boolean | NOT NULL DEFAULT false | |
release_family_name | boolean | NOT NULL DEFAULT false | |
release_suffix | boolean | NOT NULL DEFAULT false | |
release_email | boolean | NOT NULL DEFAULT false | |
release_home_ou | boolean | NOT NULL DEFAULT false | |
release_barcode | boolean | NOT NULL DEFAULT false |
Table: config.openathens_name_field
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: config.openathens_uid_field
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: config.org_unit_setting_type
F-Key | Name | Type | Description |
---|---|---|---|
name | text | PRIMARY KEY | |
label | text | UNIQUE NOT NULL | |
config.settings_group.name | grp | text | |
description | text | ||
datatype | text | NOT NULL DEFAULT 'string'::text | |
fm_class | text | ||
permission.perm_list.id | view_perm | integer | |
permission.perm_list.id | update_perm | integer |
Name | Constraint |
---|---|
coust_no_empty_link | CHECK ((((datatype = 'link'::text) AND (fm_class IS NOT NULL)) OR ((datatype <> 'link'::text) AND (fm_class IS NULL)))) |
coust_valid_datatype | CHECK ((datatype = ANY (ARRAY['bool'::text, 'integer'::text, 'float'::text, 'currency'::text, 'interval'::text, 'date'::text, 'string'::text, 'object'::text, 'array'::text, 'link'::text]))) |
Tables referencing this one via Foreign Key Constraints:
Table: config.org_unit_setting_type_log
Org Unit setting Logs This table contains the most recent changes to each setting in actor.org_unit_setting, allowing for mistakes to be undone. This is NOT meant to be an auditor, but rather an undo/redo.
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
date_applied | timestamp with time zone | NOT NULL DEFAULT now() | |
actor.org_unit.id | org | integer | |
original_value | text | ||
new_value | text | ||
config.org_unit_setting_type.name | field_name | text |
Table: config.print_template
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE#1 NOT NULL | |
label | text | UNIQUE#2 NOT NULL | |
actor.org_unit.id | owner | integer | UNIQUE#2 UNIQUE#1 NOT NULL |
active | boolean | NOT NULL DEFAULT false | |
config.i18n_locale.code | locale | text | |
content_type | text | NOT NULL DEFAULT 'text/html'::text | |
template | text | NOT NULL |
Table: config.record_attr_definition
F-Key | Name | Type | Description |
---|---|---|---|
name | text | PRIMARY KEY | |
label | text | NOT NULL | |
description | text | ||
multi | boolean | NOT NULL DEFAULT true | |
filter | boolean | NOT NULL DEFAULT true | |
sorter | boolean | NOT NULL DEFAULT false | |
composite | boolean | NOT NULL DEFAULT false | |
tag | text | ||
sf_list | text | ||
joiner | text | ||
xpath | text | ||
config.xml_transform.name | format | text | |
start_pos | integer | ||
string_len | integer | ||
fixed_field | text | ||
config.marc21_physical_characteristic_subfield_map.id | phys_char_sf | integer | |
vocabulary | text |
Tables referencing this one via Foreign Key Constraints:
Table: config.record_attr_index_norm_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
config.record_attr_definition.name | attr | text | NOT NULL |
config.index_normalizer.id | norm | integer | NOT NULL |
params | text | ||
pos | integer | NOT NULL |
Table: config.remote_account
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
label | text | NOT NULL | |
host | text | NOT NULL | |
username | text | ||
password | text | ||
account | text | ||
path | text | ||
actor.org_unit.id | owner | integer | NOT NULL |
last_activity | timestamp with time zone |
Table: config.remoteauth_profile
F-Key | Name | Type | Description |
---|---|---|---|
name | text | PRIMARY KEY | |
description | text | ||
actor.org_unit.id | context_org | integer | NOT NULL |
enabled | boolean | NOT NULL DEFAULT false | |
permission.perm_list.id | perm | integer | NOT NULL |
restrict_to_org | boolean | NOT NULL DEFAULT true | |
allow_inactive | boolean | NOT NULL DEFAULT false | |
allow_expired | boolean | NOT NULL DEFAULT false | |
block_list | text | ||
config.usr_activity_type.id | usr_activity_type | integer |
Table: config.rule_age_hold_protect
Hold Item Age Protection rules A hold request can only capture new(ish) items when they are within a particular proximity of the pickup_lib of the request. The proximity ('prox' column) is calculated by counting the number of tree edges between the pickup_lib and either the owning_lib or circ_lib of the copy that could fulfill the hold, as determined by the distance_is_from_owner value of the hold matrix rule controlling the hold request.
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE NOT NULL | |
age | interval | NOT NULL | |
prox | integer | NOT NULL |
Name | Constraint |
---|---|
rule_age_hold_protect_name_check | CHECK ((name ~ '^\w+$'::text)) |
Tables referencing this one via Foreign Key Constraints:
Table: config.rule_circ_duration
Circulation Duration rules Each circulation is given a duration based on one of these rules.
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE NOT NULL | |
extended | interval | NOT NULL | |
normal | interval | NOT NULL | |
shrt | interval | NOT NULL | |
max_renewals | integer | NOT NULL | |
max_auto_renewals | integer |
Name | Constraint |
---|---|
rule_circ_duration_name_check | CHECK ((name ~ '^\w+$'::text)) |
Tables referencing this one via Foreign Key Constraints:
Table: config.rule_max_fine
Circulation Max Fine rules Each circulation is given a maximum fine based on one of these rules.
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE NOT NULL | |
amount | numeric(6,2) | NOT NULL | |
is_percent | boolean | NOT NULL DEFAULT false |
Name | Constraint |
---|---|
rule_max_fine_name_check | CHECK ((name ~ '^\w+$'::text)) |
Tables referencing this one via Foreign Key Constraints:
Table: config.rule_recurring_fine
Circulation Recurring Fine rules Each circulation is given a recurring fine amount based on one of these rules. Note that it is recommended to run the fine generator (from cron) at least as frequently as the lowest recurrence interval used by your circulation rules so that accrued fines will be up to date.
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE NOT NULL | |
high | numeric(6,2) | NOT NULL | |
normal | numeric(6,2) | NOT NULL | |
low | numeric(6,2) | NOT NULL | |
recurrence_interval | interval | NOT NULL DEFAULT '1 day'::interval | |
grace_period | interval | NOT NULL DEFAULT '1 day'::interval |
Name | Constraint |
---|---|
rule_recurring_fine_name_check | CHECK ((name ~ '^\w+$'::text)) |
Tables referencing this one via Foreign Key Constraints:
Table: config.settings_group
F-Key | Name | Type | Description |
---|---|---|---|
name | text | PRIMARY KEY | |
label | text | UNIQUE NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: config.sms_carrier
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
region | text | ||
name | text | ||
email_gateway | text | ||
active | boolean | DEFAULT true |
Tables referencing this one via Foreign Key Constraints:
Table: config.standing
Patron Standings This table contains the values that can be applied to a patron by a staff member. These values should not be changed, other than for translation, as the ID column is currently a "magic number" in the source. :(
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
value | text | UNIQUE NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: config.standing_penalty
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE NOT NULL | |
label | text | NOT NULL | |
block_list | text | ||
staff_alert | boolean | NOT NULL DEFAULT false | |
org_depth | integer | ||
ignore_proximity | integer |
Tables referencing this one via Foreign Key Constraints:
Table: config.ts_config_list
Full Text Configs A list of full text configs with names and descriptions.
F-Key | Name | Type | Description |
---|---|---|---|
id | text | PRIMARY KEY | |
name | text | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: config.ui_staff_portal_page_entry
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
page_col | integer | NOT NULL | |
col_pos | integer | NOT NULL | |
config.ui_staff_portal_page_entry_type.code | entry_type | text | NOT NULL |
label | text | ||
image_url | text | ||
target_url | text | ||
entry_text | text | ||
actor.org_unit.id | owner | integer | NOT NULL |
Table: config.ui_staff_portal_page_entry_type
F-Key | Name | Type | Description |
---|---|---|---|
code | text | PRIMARY KEY | |
label | text | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: config.upgrade_log
F-Key | Name | Type | Description |
---|---|---|---|
version | text | PRIMARY KEY | |
install_date | timestamp with time zone | NOT NULL DEFAULT now() | |
applied_to | text |
Table: config.usr_activity_type
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
ewho | text | ||
ewhat | text | ||
ehow | text | ||
label | text | NOT NULL | |
egroup | config.usr_activity_group | NOT NULL | |
enabled | boolean | NOT NULL DEFAULT true | |
transient | boolean | NOT NULL DEFAULT true |
Name | Constraint |
---|---|
one_of_wwh | CHECK ((COALESCE(ewho, ewhat, ehow) IS NOT NULL)) |
Tables referencing this one via Foreign Key Constraints:
Table: config.usr_setting_type
F-Key | Name | Type | Description |
---|---|---|---|
name | text | PRIMARY KEY | |
opac_visible | boolean | NOT NULL DEFAULT false | |
label | text | UNIQUE NOT NULL | |
description | text | ||
config.settings_group.name | grp | text | |
datatype | text | NOT NULL DEFAULT 'string'::text | |
fm_class | text | ||
reg_default | text |
Name | Constraint |
---|---|
coust_no_empty_link | CHECK ((((datatype = 'link'::text) AND (fm_class IS NOT NULL)) OR ((datatype <> 'link'::text) AND (fm_class IS NULL)))) |
coust_valid_datatype | CHECK ((datatype = ANY (ARRAY['bool'::text, 'integer'::text, 'float'::text, 'currency'::text, 'interval'::text, 'date'::text, 'string'::text, 'object'::text, 'array'::text, 'link'::text]))) |
Tables referencing this one via Foreign Key Constraints:
View: config.videorecording_format_map
F-Key | Name | Type | Description |
---|---|---|---|
code | text | ||
value | text |
SELECT coded_value_map.code , coded_value_map.value FROM config.coded_value_map WHERE (coded_value_map.ctype = 'vr_format'::text);
Table: config.weight_assoc
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
active | boolean | NOT NULL | |
actor.org_unit.id | org_unit | integer | NOT NULL |
config.circ_matrix_weights.id | circ_weights | integer | |
config.hold_matrix_weights.id | hold_weights | integer |
Table: config.workstation_setting_type
F-Key | Name | Type | Description |
---|---|---|---|
name | text | PRIMARY KEY | |
label | text | UNIQUE NOT NULL | |
config.settings_group.name | grp | text | |
description | text | ||
datatype | text | NOT NULL DEFAULT 'string'::text | |
fm_class | text |
Name | Constraint |
---|---|
cwst_no_empty_link | CHECK ((((datatype = 'link'::text) AND (fm_class IS NOT NULL)) OR ((datatype <> 'link'::text) AND (fm_class IS NULL)))) |
cwst_valid_datatype | CHECK ((datatype = ANY (ARRAY['bool'::text, 'integer'::text, 'float'::text, 'currency'::text, 'interval'::text, 'date'::text, 'string'::text, 'object'::text, 'array'::text, 'link'::text]))) |
Tables referencing this one via Foreign Key Constraints:
Table: config.xml_transform
F-Key | Name | Type | Description |
---|---|---|---|
name | text | PRIMARY KEY | |
namespace_uri | text | NOT NULL | |
prefix | text | NOT NULL | |
xslt | text | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: config.z3950_attr
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
config.z3950_source.name | source | text | UNIQUE#1 NOT NULL |
name | text | NOT NULL | |
label | text | NOT NULL | |
code | integer | UNIQUE#1 NOT NULL | |
format | integer | UNIQUE#1 NOT NULL | |
truncation | integer | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: config.z3950_index_field_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
label | text | NOT NULL | |
config.metabib_field.id | metabib_field | integer | |
config.record_attr_definition.name | record_attr | text | |
config.z3950_attr.id | z3950_attr | integer | |
z3950_attr_type | text |
Name | Constraint |
---|---|
attr_or_attr_type | CHECK (((z3950_attr IS NOT NULL) OR (z3950_attr_type IS NOT NULL))) |
metabib_field_or_record_attr | CHECK (((metabib_field IS NOT NULL) OR (record_attr IS NOT NULL))) |
Table: config.z3950_source
Z39.50 Sources Each row in this table represents a database searchable via Z39.50.
F-Key | Name | Type | Description |
---|---|---|---|
name | text | PRIMARY KEY | |
label | text | UNIQUE NOT NULL | |
host | text | NOT NULL | |
port | integer | NOT NULL | |
db | text | NOT NULL | |
record_format | text |
NOT NULL
DEFAULT 'FI'::text
Z39.50 element set. |
|
transmission_format | text |
NOT NULL
DEFAULT 'usmarc'::text
Z39.50 preferred record syntax.. |
|
auth | boolean | NOT NULL DEFAULT true | |
permission.perm_list.id | use_perm | integer |
If set, this permission is required for the source to be listed in the staff client Z39.50 interface. Similar to permission.grp_tree.application_perm. |
Tables referencing this one via Foreign Key Constraints:
Table: config.z3950_source_credentials
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | owner | integer | UNIQUE#1 NOT NULL |
config.z3950_source.name | source | text | UNIQUE#1 NOT NULL |
username | text | ||
password | text |
Function: config.interval_to_seconds(interval_string text)
Returns: integer
Language: PLPGSQL
BEGIN RETURN config.interval_to_seconds( interval_string::INTERVAL ); END;
Function: config.interval_to_seconds(interval_val interval)
Returns: integer
Language: PLPGSQL
BEGIN RETURN EXTRACT( EPOCH FROM interval_val ); END;
Function: config.ou_marc_fields(ou integer, marc_record_type config.marc_record_type, marc_format integer)
Returns: SET OF marc_field
Language: SQL
SELECT id, marc_format, marc_record_type, tag, name, description, fixed_field, repeatable, mandatory, hidden, owner FROM ( SELECT id, marc_format, marc_record_type, tag, name, description, fixed_field, repeatable, mandatory, hidden, owner, depth, MAX(depth) OVER (PARTITION BY marc_format, marc_record_type, tag) AS winner FROM config.marc_field_for_ou WHERE (owner IS NULL OR owner IN (SELECT id FROM actor.org_unit_ancestors($3))) AND marc_format = $1 AND marc_record_type = $2 ) AS s WHERE depth = winner AND not hidden;
Function: config.ou_marc_subfields(ou integer, marc_record_type config.marc_record_type, marc_format integer)
Returns: SET OF marc_subfield
Language: SQL
SELECT id, marc_format, marc_record_type, tag, code, description, repeatable, mandatory, hidden, value_ctype, owner FROM ( SELECT id, marc_format, marc_record_type, tag, code, description, repeatable, mandatory, hidden, value_ctype, owner, depth, MAX(depth) OVER (PARTITION BY marc_format, marc_record_type, tag, code) AS winner FROM config.marc_subfield_for_ou WHERE (owner IS NULL OR owner IN (SELECT id FROM actor.org_unit_ancestors($3))) AND marc_format = $1 AND marc_record_type = $2 ) AS s WHERE depth = winner AND not hidden;
Function: config.setting_is_user_or_ws()
Returns: trigger
Language: PLPGSQL
BEGIN IF TG_TABLE_NAME = 'usr_setting_type' THEN PERFORM TRUE FROM config.workstation_setting_type cwst WHERE cwst.name = NEW.name; IF NOT FOUND THEN RETURN NULL; END IF; END IF; IF TG_TABLE_NAME = 'workstation_setting_type' THEN PERFORM TRUE FROM config.usr_setting_type cust WHERE cust.name = NEW.name; IF NOT FOUND THEN RETURN NULL; END IF; END IF; RAISE EXCEPTION '% Cannot be used as both a user setting and a workstation setting.', NEW.name; END;
Function: config.update_coded_value_map(add_only text, in_is_simple text, in_search_label text, in_opac_visible text, in_description boolean, in_value text, in_code boolean, in_ctype boolean)
Returns: void
Language: PLPGSQL
DECLARE current_row config.coded_value_map%ROWTYPE; BEGIN -- Look for a current value SELECT INTO current_row * FROM config.coded_value_map WHERE ctype = in_ctype AND code = in_code; -- If we have one.. IF FOUND AND NOT add_only THEN -- Update anything we were handed current_row.value := COALESCE(current_row.value, in_value); current_row.description := COALESCE(current_row.description, in_description); current_row.opac_visible := COALESCE(current_row.opac_visible, in_opac_visible); current_row.search_label := COALESCE(current_row.search_label, in_search_label); current_row.is_simple := COALESCE(current_row.is_simple, in_is_simple); UPDATE config.coded_value_map SET value = current_row.value, description = current_row.description, opac_visible = current_row.opac_visible, search_label = current_row.search_label, is_simple = current_row.is_simple WHERE id = current_row.id; ELSE INSERT INTO config.coded_value_map(ctype, code, value, description, opac_visible, search_label, is_simple) VALUES (in_ctype, in_code, in_value, in_description, COALESCE(in_opac_visible, TRUE), in_search_label, COALESCE(in_is_simple, FALSE)); END IF; END;
Function: config.update_hard_due_dates()
Returns: integer
Language: PLPGSQL
DECLARE temp_value config.hard_due_date_values%ROWTYPE; updated INT := 0; BEGIN FOR temp_value IN SELECT DISTINCT ON (hard_due_date) * FROM config.hard_due_date_values WHERE active_date <= NOW() -- We've passed (or are at) the rollover time ORDER BY hard_due_date, active_date DESC -- Latest (nearest to us) active time LOOP UPDATE config.hard_due_date SET ceiling_date = temp_value.ceiling_date WHERE id = temp_value.hard_due_date AND ceiling_date <> temp_value.ceiling_date -- Time is equal if we've already updated the chdd AND temp_value.ceiling_date >= NOW(); -- Don't update ceiling dates to the past IF FOUND THEN updated := updated + 1; END IF; END LOOP; RETURN updated; END;
Function: config.z3950_source_credentials_apply(passwd text, uname integer, org text, src text)
Returns: void
Language: PLPGSQL
BEGIN PERFORM 1 FROM config.z3950_source_credentials WHERE owner = org AND source = src; IF FOUND THEN IF COALESCE(uname, '') = '' AND COALESCE(passwd, '') = '' THEN DELETE FROM config.z3950_source_credentials WHERE owner = org AND source = src; ELSE UPDATE config.z3950_source_credentials SET username = uname, password = passwd WHERE owner = org AND source = src; END IF; ELSE IF COALESCE(uname, '') <> '' OR COALESCE(passwd, '') <> '' THEN INSERT INTO config.z3950_source_credentials (source, owner, username, password) VALUES (src, org, uname, passwd); END IF; END IF; END;
Function: config.z3950_source_credentials_lookup(owner text, source integer)
Returns: z3950_source_credentials
Language: SQL
SELECT creds.* FROM config.z3950_source_credentials creds JOIN actor.org_unit aou ON (aou.id = creds.owner) JOIN actor.org_unit_type aout ON (aout.id = aou.ou_type) WHERE creds.source = $1 AND creds.owner IN ( SELECT id FROM actor.org_unit_ancestors($2) ) ORDER BY aout.depth DESC LIMIT 1;
Schema container
Table: container.biblio_record_entry_bucket
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.usr.id | owner | integer | UNIQUE#1 NOT NULL |
name | text | UNIQUE#1 NOT NULL | |
container.biblio_record_entry_bucket_type.code | btype | text | UNIQUE#1 NOT NULL DEFAULT 'misc'::text |
description | text | ||
pub | boolean | NOT NULL DEFAULT false | |
actor.org_unit.id | owning_lib | integer | |
create_time | timestamp with time zone | NOT NULL DEFAULT now() |
Tables referencing this one via Foreign Key Constraints:
Table: container.biblio_record_entry_bucket_item
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
container.biblio_record_entry_bucket.id | bucket | integer | NOT NULL |
biblio.record_entry.id | target_biblio_record_entry | bigint | NOT NULL |
pos | integer | ||
create_time | timestamp with time zone | NOT NULL DEFAULT now() |
Tables referencing this one via Foreign Key Constraints:
Table: container.biblio_record_entry_bucket_item_note
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
container.biblio_record_entry_bucket_item.id | item | integer | NOT NULL |
note | text | NOT NULL |
Table: container.biblio_record_entry_bucket_note
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
container.biblio_record_entry_bucket.id | bucket | integer | NOT NULL |
note | text | NOT NULL |
Table: container.biblio_record_entry_bucket_type
F-Key | Name | Type | Description |
---|---|---|---|
code | text | PRIMARY KEY | |
label | text | UNIQUE NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: container.call_number_bucket
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.usr.id | owner | integer | UNIQUE#1 NOT NULL |
name | text | UNIQUE#1 NOT NULL | |
container.call_number_bucket_type.code | btype | text | UNIQUE#1 NOT NULL DEFAULT 'misc'::text |
description | text | ||
pub | boolean | NOT NULL DEFAULT false | |
actor.org_unit.id | owning_lib | integer | |
create_time | timestamp with time zone | NOT NULL DEFAULT now() |
Tables referencing this one via Foreign Key Constraints:
Table: container.call_number_bucket_item
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
container.call_number_bucket.id | bucket | integer | NOT NULL |
asset.call_number.id | target_call_number | integer | NOT NULL |
pos | integer | ||
create_time | timestamp with time zone | NOT NULL DEFAULT now() |
Tables referencing this one via Foreign Key Constraints:
Table: container.call_number_bucket_item_note
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
container.call_number_bucket_item.id | item | integer | NOT NULL |
note | text | NOT NULL |
Table: container.call_number_bucket_note
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
container.call_number_bucket.id | bucket | integer | NOT NULL |
note | text | NOT NULL |
Table: container.call_number_bucket_type
F-Key | Name | Type | Description |
---|---|---|---|
code | text | PRIMARY KEY | |
label | text | UNIQUE NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: container.carousel
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
config.carousel_type.id | type | integer | NOT NULL |
actor.org_unit.id | owner | integer | NOT NULL |
name | text | NOT NULL | |
container.biblio_record_entry_bucket.id | bucket | integer | |
actor.usr.id | creator | integer | NOT NULL |
actor.usr.id | editor | integer | NOT NULL |
create_time | timestamp with time zone | NOT NULL DEFAULT now() | |
edit_time | timestamp with time zone | NOT NULL DEFAULT now() | |
age_filter | interval | ||
owning_lib_filter | integer[] | ||
copy_location_filter | integer[] | ||
last_refresh_time | timestamp with time zone | ||
active | boolean | NOT NULL DEFAULT true | |
max_items | integer | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: container.carousel_org_unit
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
container.carousel.id | carousel | integer | NOT NULL |
override_name | text | ||
actor.org_unit.id | org_unit | integer | NOT NULL |
seq | integer | NOT NULL |
Table: container.copy_bucket
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.usr.id | owner | integer | UNIQUE#1 NOT NULL |
name | text | UNIQUE#1 NOT NULL | |
container.copy_bucket_type.code | btype | text | UNIQUE#1 NOT NULL DEFAULT 'misc'::text |
description | text | ||
pub | boolean | NOT NULL DEFAULT false | |
actor.org_unit.id | owning_lib | integer | |
create_time | timestamp with time zone | NOT NULL DEFAULT now() |
Tables referencing this one via Foreign Key Constraints:
Table: container.copy_bucket_item
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
container.copy_bucket.id | bucket | integer | NOT NULL |
target_copy | integer | NOT NULL | |
pos | integer | ||
create_time | timestamp with time zone | NOT NULL DEFAULT now() |
Tables referencing this one via Foreign Key Constraints:
copy_bucket_item_bucket_idx bucketTable: container.copy_bucket_item_note
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
container.copy_bucket_item.id | item | integer | NOT NULL |
note | text | NOT NULL |
Table: container.copy_bucket_note
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
container.copy_bucket.id | bucket | integer | NOT NULL |
note | text | NOT NULL |
Table: container.copy_bucket_type
F-Key | Name | Type | Description |
---|---|---|---|
code | text | PRIMARY KEY | |
label | text | UNIQUE NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: container.user_bucket
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.usr.id | owner | integer | UNIQUE#1 NOT NULL |
name | text | UNIQUE#1 NOT NULL | |
container.user_bucket_type.code | btype | text | UNIQUE#1 NOT NULL DEFAULT 'misc'::text |
description | text | ||
pub | boolean | NOT NULL DEFAULT false | |
actor.org_unit.id | owning_lib | integer | |
create_time | timestamp with time zone | NOT NULL DEFAULT now() |
Tables referencing this one via Foreign Key Constraints:
Table: container.user_bucket_item
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
container.user_bucket.id | bucket | integer | NOT NULL |
actor.usr.id | target_user | integer | NOT NULL |
pos | integer | ||
create_time | timestamp with time zone | NOT NULL DEFAULT now() |
Tables referencing this one via Foreign Key Constraints:
user_bucket_item_target_user_idx target_userTable: container.user_bucket_item_note
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
container.user_bucket_item.id | item | integer | NOT NULL |
note | text | NOT NULL |
Table: container.user_bucket_note
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
container.user_bucket.id | bucket | integer | NOT NULL |
note | text | NOT NULL |
Table: container.user_bucket_type
F-Key | Name | Type | Description |
---|---|---|---|
code | text | PRIMARY KEY | |
label | text | UNIQUE NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Function: container.clear_all_expired_circ_history_items()
Returns: void
Language: PLPGSQL
Delete expired circulation bucket items for all users that have a setting for patron.max_reading_list_interval.
-- -- Delete expired circulation bucket items for all users that have -- a setting for patron.max_reading_list_interval. -- DECLARE today TIMESTAMP WITH TIME ZONE; threshold TIMESTAMP WITH TIME ZONE; usr_setting RECORD; BEGIN SELECT date_trunc( 'day', now() ) INTO today; -- FOR usr_setting in SELECT usr, value FROM actor.usr_setting WHERE name = 'patron.max_reading_list_interval' LOOP -- -- Make sure the setting is a valid interval -- BEGIN threshold := today - CAST( translate( usr_setting.value, '"', '' ) AS INTERVAL ); EXCEPTION WHEN OTHERS THEN RAISE NOTICE 'Invalid setting patron.max_reading_list_interval for user %: ''%''', usr_setting.usr, usr_setting.value; CONTINUE; END; -- --RAISE NOTICE 'User % threshold %', usr_setting.usr, threshold; -- DELETE FROM container.copy_bucket_item WHERE bucket IN ( SELECT id FROM container.copy_bucket WHERE owner = usr_setting.usr AND btype = 'circ_history' ) AND create_time < threshold; END LOOP; -- END;
Function: container.clear_expired_circ_history_items(ac_usr integer)
Returns: void
Language: PLPGSQL
Delete old circulation bucket items for a specified user. "Old" means older than the interval specified by a user-level setting, if it is so specified.
-- -- Delete old circulation bucket items for a specified user. -- "Old" means older than the interval specified by a -- user-level setting, if it is so specified. -- DECLARE threshold TIMESTAMP WITH TIME ZONE; BEGIN -- Sanity check IF ac_usr IS NULL THEN RETURN; END IF; -- Determine the threshold date that defines "old". Subtract the -- interval from the system date, then truncate to midnight. SELECT date_trunc( 'day', now() - CAST( translate( value, '"', '' ) AS INTERVAL ) ) INTO threshold FROM actor.usr_setting WHERE usr = ac_usr AND name = 'patron.max_reading_list_interval'; -- IF threshold is null THEN -- No interval defined; don't delete anything -- RAISE NOTICE 'No interval defined for user %', ac_usr; return; END IF; -- -- RAISE NOTICE 'Date threshold: %', threshold; -- -- Threshold found; do the delete delete from container.copy_bucket_item where bucket in ( select id from container.copy_bucket where owner = ac_usr and btype = 'circ_history' ) and create_time < threshold; -- RETURN; END;
Schema evergreen
Function: evergreen.array_overlap_check()
Returns: trigger
Language: PLPGSQL
DECLARE fld TEXT; cnt INT; BEGIN fld := TG_ARGV[0]; EXECUTE 'SELECT COUNT(*) FROM '|| TG_TABLE_SCHEMA ||'.'|| TG_TABLE_NAME ||' WHERE '|| fld ||' && ($1).'|| fld INTO cnt USING NEW; IF cnt > 0 THEN RAISE EXCEPTION 'Cannot insert duplicate array into field % of table %', fld, TG_TABLE_SCHEMA ||'.'|| TG_TABLE_NAME; END IF; RETURN NEW; END;
Function: evergreen.asset_copy_alert_copy_inh_fkey()
Returns: trigger
Language: PLPGSQL
BEGIN PERFORM 1 FROM asset.copy WHERE id = NEW.copy; IF NOT FOUND THEN RAISE foreign_key_violation USING MESSAGE = FORMAT( $$Referenced asset.copy id not found, copy:%s$$, NEW.copy ); END IF; RETURN NEW; END;
Function: evergreen.asset_copy_inventory_copy_inh_fkey()
Returns: trigger
Language: PLPGSQL
BEGIN PERFORM 1 FROM asset.copy WHERE id = NEW.copy; IF NOT FOUND THEN RAISE foreign_key_violation USING MESSAGE = FORMAT( $$Referenced asset.copy id not found, copy:%s$$, NEW.copy ); END IF; RETURN NEW; END;
Function: evergreen.asset_copy_note_owning_copy_inh_fkey()
Returns: trigger
Language: PLPGSQL
BEGIN PERFORM 1 FROM asset.copy WHERE id = NEW.owning_copy; IF NOT FOUND THEN RAISE foreign_key_violation USING MESSAGE = FORMAT( $$Referenced asset.copy id not found, owning_copy:%s$$, NEW.owning_copy ); END IF; RETURN NEW; END;
Function: evergreen.asset_copy_tag_copy_map_copy_inh_fkey()
Returns: trigger
Language: PLPGSQL
BEGIN PERFORM 1 FROM asset.copy WHERE id = NEW.copy; IF NOT FOUND THEN RAISE foreign_key_violation USING MESSAGE = FORMAT( $$Referenced asset.copy id not found, copy:%s$$, NEW.copy ); END IF; RETURN NEW; END;
Function: evergreen.can_float(to_ou integer, from_ou integer, copy_floating_group integer)
Returns: boolean
Language: PLPGSQL
DECLARE float_member config.floating_group_member%ROWTYPE; shared_ou_depth INT; to_ou_depth INT; BEGIN -- Grab the shared OU depth. If this is less than the stop depth later we ignore the entry. SELECT INTO shared_ou_depth max(depth) FROM actor.org_unit_common_ancestors( from_ou, to_ou ) aou JOIN actor.org_unit_type aout ON aou.ou_type = aout.id; -- Grab the to ou depth. If this is greater than max depth we ignore the entry. SELECT INTO to_ou_depth depth FROM actor.org_unit aou JOIN actor.org_unit_type aout ON aou.ou_type = aout.id WHERE aou.id = to_ou; -- Grab float members that apply. We don't care what we get beyond wanting excluded ones first. SELECT INTO float_member * FROM config.floating_group_member cfgm JOIN actor.org_unit aou ON cfgm.org_unit = aou.id JOIN actor.org_unit_type aout ON aou.ou_type = aout.id WHERE cfgm.floating_group = copy_floating_group AND to_ou IN (SELECT id FROM actor.org_unit_descendants(aou.id)) AND cfgm.stop_depth <= shared_ou_depth AND (cfgm.max_depth IS NULL OR to_ou_depth <= max_depth) ORDER BY exclude DESC; -- If we found something then we want to return the opposite of the exclude flag IF FOUND THEN RETURN NOT float_member.exclude; END IF; -- Otherwise no floating. RETURN false; END;
Function: evergreen.change_db_setting(settings text, setting_name text[])
Returns: void
Language: PLPGSQL
BEGIN EXECUTE 'ALTER DATABASE ' || quote_ident(current_database()) || ' SET ' || quote_ident(setting_name) || ' = ' || array_to_string(settings, ','); END;
Function: evergreen.coded_value_map_normalizer(ctype text, input text)
Returns: text
Language: SQL
SELECT COALESCE(value,$1) FROM config.coded_value_map WHERE ctype = $2 AND code = $1;
Function: evergreen.container_copy_bucket_item_target_copy_inh_fkey()
Returns: trigger
Language: PLPGSQL
BEGIN PERFORM 1 FROM asset.copy WHERE id = NEW.target_copy; IF NOT FOUND THEN RAISE foreign_key_violation USING MESSAGE = FORMAT( $$Referenced asset.copy id not found, target_copy:%s$$, NEW.target_copy ); END IF; RETURN NEW; END;
Function: evergreen.could_be_serial_holding_code(text)
Returns: boolean
Language: PLPERLU
Return true if parameter is valid JSON representing an array that at minimum doesn't make MARC::Field balk and only has subfield labels exactly one character long. Otherwise false.
use JSON::XS; use MARC::Field; eval { my $holding_code = (new JSON::XS)->decode(shift); new MARC::Field('999', @$holding_code); }; return 0 if $@; # verify that subfield labels are exactly one character long foreach (keys %{ { @$holding_code } }) { return 0 if length($_) != 1; } return 1;
Function: evergreen.display_field_force_nfc()
Returns: trigger
Language: PLPGSQL
BEGIN NEW.value := force_unicode_normal_form(NEW.value,'NFC'); RETURN NEW; END;
Function: evergreen.escape_for_html(text)
Returns: text
Language: SQL
SELECT regexp_replace( regexp_replace( regexp_replace( $1, '&', '&', 'g' ), '<', '<', 'g' ), '>', '>', 'g' );
Function: evergreen.extract_marc_field(text, bigint, text)
Returns: text
Language: SQL
SELECT extract_marc_field($1,$2,$3,'');
Function: evergreen.extract_marc_field(text, bigint, text, text)
Returns: text
Language: PLPGSQL
DECLARE query TEXT; output TEXT; BEGIN query := $q$ SELECT regexp_replace( oils_xpath_string( $q$ || quote_literal($3) || $q$, marc, ' ' ), $q$ || quote_literal($4) || $q$, '', 'g') FROM $q$ || $1 || $q$ WHERE id = $q$ || $2; EXECUTE query INTO output; -- RAISE NOTICE 'query: %, output; %', query, output; RETURN output; END;
Function: evergreen.extract_marc_field_set(text, bigint, text, text)
Returns: SET OF text
Language: PLPGSQL
DECLARE query TEXT; output TEXT; BEGIN FOR output IN SELECT x.t FROM ( SELECT id,t FROM oils_xpath_table( 'id', 'marc', $1, $3, 'id = ' || $2) AS t(id int, t text))x LOOP IF $4 IS NOT NULL THEN SELECT INTO output (SELECT regexp_replace(output, $4, '', 'g')); END IF; RETURN NEXT output; END LOOP; RETURN; END;
Function: evergreen.facet_force_nfc()
Returns: trigger
Language: PLPGSQL
BEGIN NEW.value := force_unicode_normal_form(NEW.value,'NFC'); RETURN NEW; END;
Function: evergreen.fake_fkey_tgr()
Returns: trigger
Language: PLPGSQL
DECLARE copy_id BIGINT; BEGIN EXECUTE 'SELECT ($1).' || quote_ident(TG_ARGV[0]) INTO copy_id USING NEW; IF copy_id IS NOT NULL THEN PERFORM * FROM asset.copy WHERE id = copy_id; IF NOT FOUND THEN RAISE EXCEPTION 'Key (%.%=%) does not exist in asset.copy', TG_TABLE_SCHEMA, TG_TABLE_NAME, copy_id; END IF; END IF; RETURN NULL; END;
Function: evergreen.find_next_open_time(dow_count integer, initial_time timestamp with time zone, hourly boolean, initial time without time zone, circ_lib integer)
Returns: timestamp with time zone
Language: PLPGSQL
DECLARE day_number INT; plus_days INT; final_time TEXT; time_adjusted BOOL; hoo_open TIME WITHOUT TIME ZONE; hoo_close TIME WITHOUT TIME ZONE; adjacent actor.org_unit_closed%ROWTYPE; breakout INT := 0; BEGIN IF dow_count > 6 THEN RETURN initial; END IF; IF initial_time IS NULL THEN initial_time := initial::TIME; END IF; final_time := (initial + '1 second'::INTERVAL)::TEXT; LOOP breakout := breakout + 1; time_adjusted := FALSE; IF dow_count > 0 THEN -- we're recursing, so check for HOO closing day_number := EXTRACT(ISODOW FROM final_time::TIMESTAMPTZ) - 1; plus_days := 0; FOR i IN 1..7 LOOP EXECUTE 'SELECT dow_' || day_number || '_open, dow_' || day_number || '_close FROM actor.hours_of_operation WHERE id = $1' INTO hoo_open, hoo_close USING circ_lib; -- RAISE NOTICE 'initial time: %; dow: %; close: %',initial_time,day_number,hoo_close; IF hoo_close = '00:00:00' THEN -- bah ... I guess we'll check the next day day_number := (day_number + 1) % 7; plus_days := plus_days + 1; time_adjusted := TRUE; CONTINUE; END IF; IF hoo_close IS NULL THEN -- no hours of operation ... assume no closing? hoo_close := '23:59:59'; END IF; EXIT; END LOOP; final_time := DATE(final_time::TIMESTAMPTZ + (plus_days || ' days')::INTERVAL)::TEXT; IF hoo_close <> '00:00:00' AND hourly THEN -- Not a day-granular circ final_time := final_time||' '|| hoo_close; ELSE final_time := final_time||' 23:59:59'; END IF; END IF; -- Loop through other closings LOOP SELECT * INTO adjacent FROM actor.org_unit_closed WHERE org_unit = circ_lib AND final_time::TIMESTAMPTZ between close_start AND close_end; EXIT WHEN adjacent.id IS NULL; time_adjusted := TRUE; -- RAISE NOTICE 'recursing for closings with final_time: %',final_time; final_time := evergreen.find_next_open_time(circ_lib, adjacent.close_end::TIMESTAMPTZ, hourly, initial_time, dow_count + 1)::TEXT; END LOOP; EXIT WHEN breakout > 100; EXIT WHEN NOT time_adjusted; END LOOP; RETURN final_time; END;
Function: evergreen.force_unicode_normal_form(form text, string text)
Returns: text
Language: PLPERLU
use Unicode::Normalize 'normalize'; return normalize($_[1],$_[0]); # reverse the params
Function: evergreen.generic_map_normalizer(text, text)
Returns: text
Language: PLPERLU
my $string = shift; my %map; my $default = $string; $_ = shift; while (/^\s*?(.*?)\s*?=>\s*?(\S+)\s*/) { if ($1 eq '') { $default = $2; } else { $map{$2} = [split(/\s*,\s*/, $1)]; } $_ = $'; } for my $key ( keys %map ) { return $key if (grep { $_ eq $string } @{ $map{$key} }); } return $default;
Function: evergreen.get_barcodes(in_barcode integer, type text, select_ou text)
Returns: SET OF barcode_set
Language: PLPGSQL
Given user input, find an appropriate barcode in the proper class. Will add prefix/suffix information to do so, and return all results.
DECLARE cur_barcode TEXT; barcode_len INT; completion_len INT; asset_barcodes TEXT[]; actor_barcodes TEXT[]; do_asset BOOL = false; do_serial BOOL = false; do_booking BOOL = false; do_actor BOOL = false; completion_set config.barcode_completion%ROWTYPE; BEGIN IF position('asset' in type) > 0 THEN do_asset = true; END IF; IF position('serial' in type) > 0 THEN do_serial = true; END IF; IF position('booking' in type) > 0 THEN do_booking = true; END IF; IF do_asset OR do_serial OR do_booking THEN asset_barcodes = asset_barcodes || in_barcode; END IF; IF position('actor' in type) > 0 THEN do_actor = true; actor_barcodes = actor_barcodes || in_barcode; END IF; barcode_len := length(in_barcode); FOR completion_set IN SELECT * FROM config.barcode_completion WHERE active AND org_unit IN (SELECT aou.id FROM actor.org_unit_ancestors(select_ou) aou) LOOP IF completion_set.prefix IS NULL THEN completion_set.prefix := ''; END IF; IF completion_set.suffix IS NULL THEN completion_set.suffix := ''; END IF; IF completion_set.length = 0 OR completion_set.padding IS NULL OR length(completion_set.padding) = 0 THEN cur_barcode = completion_set.prefix || in_barcode || completion_set.suffix; ELSE completion_len = completion_set.length - length(completion_set.prefix) - length(completion_set.suffix); IF completion_len >= barcode_len THEN IF completion_set.padding_end THEN cur_barcode = rpad(in_barcode, completion_len, completion_set.padding); ELSE cur_barcode = lpad(in_barcode, completion_len, completion_set.padding); END IF; cur_barcode = completion_set.prefix || cur_barcode || completion_set.suffix; END IF; END IF; IF completion_set.actor THEN actor_barcodes = actor_barcodes || cur_barcode; END IF; IF completion_set.asset THEN asset_barcodes = asset_barcodes || cur_barcode; END IF; END LOOP; IF do_asset AND do_serial THEN RETURN QUERY SELECT 'asset'::TEXT, id, barcode FROM ONLY asset.copy WHERE barcode = ANY(asset_barcodes) AND deleted = false; RETURN QUERY SELECT 'serial'::TEXT, id, barcode FROM serial.unit WHERE barcode = ANY(asset_barcodes) AND deleted = false; ELSIF do_asset THEN RETURN QUERY SELECT 'asset'::TEXT, id, barcode FROM asset.copy WHERE barcode = ANY(asset_barcodes) AND deleted = false; ELSIF do_serial THEN RETURN QUERY SELECT 'serial'::TEXT, id, barcode FROM serial.unit WHERE barcode = ANY(asset_barcodes) AND deleted = false; END IF; IF do_booking THEN RETURN QUERY SELECT 'booking'::TEXT, id::BIGINT, barcode FROM booking.resource WHERE barcode = ANY(asset_barcodes); END IF; IF do_actor THEN RETURN QUERY SELECT 'actor'::TEXT, c.usr::BIGINT, c.barcode FROM actor.card c JOIN actor.usr u ON c.usr = u.id WHERE ((c.barcode = ANY(actor_barcodes) AND c.active) OR c.barcode = in_barcode) AND NOT u.deleted ORDER BY usr; END IF; RETURN; END;
Function: evergreen.get_locale_name(description text)
Returns: record
Language: PLPGSQL
DECLARE eg_locale TEXT; BEGIN eg_locale := LOWER(SUBSTRING(locale FROM 1 FOR 2)) || '-' || UPPER(SUBSTRING(locale FROM 4 FOR 2)); SELECT i18nc.string INTO name FROM config.i18n_locale i18nl INNER JOIN config.i18n_core i18nc ON i18nl.code = i18nc.translation WHERE i18nc.identity_value = eg_locale AND code = eg_locale AND i18nc.fq_field = 'i18n_l.name'; IF name IS NULL THEN SELECT i18nl.name INTO name FROM config.i18n_locale i18nl WHERE code = eg_locale; END IF; SELECT i18nc.string INTO description FROM config.i18n_locale i18nl INNER JOIN config.i18n_core i18nc ON i18nl.code = i18nc.translation WHERE i18nc.identity_value = eg_locale AND code = eg_locale AND i18nc.fq_field = 'i18n_l.description'; IF description IS NULL THEN SELECT i18nl.description INTO description FROM config.i18n_locale i18nl WHERE code = eg_locale; END IF; END;
Function: evergreen.is_json(text)
Returns: boolean
Language: PLPERLU
use JSON::XS; my $json = shift(); eval { JSON::XS->new->allow_nonref->decode( $json ) }; return $@ ? 0 : 1;
Function: evergreen.levenshtein_damerau_edistance( text, b text, a integer)
Returns: numeric
Language: PLPERLU
use Text::Levenshtein::Damerau::XS qw/xs_edistance/; return xs_edistance(@_);
Function: evergreen.limit_oustl()
Returns: trigger
Language: PLPGSQL
BEGIN -- Only keeps the most recent five settings changes. DELETE FROM config.org_unit_setting_type_log WHERE field_name = NEW.field_name AND org = NEW.org AND date_applied NOT IN (SELECT date_applied FROM config.org_unit_setting_type_log WHERE field_name = NEW.field_name AND org = NEW.org ORDER BY date_applied DESC LIMIT 4); IF (TG_OP = 'UPDATE') THEN RETURN NEW; ELSIF (TG_OP = 'INSERT') THEN RETURN NEW; END IF; RETURN NULL; END;
Function: evergreen.located_uris(rank bigint, label_sortkey integer, name integer)
Returns: SET OF record
Language: SQL
SELECT * FROM evergreen.located_uris(ARRAY[$1],$2,$3)
Function: evergreen.located_uris(rank bigint[], label_sortkey integer, name integer)
Returns: SET OF record
Language: SQL
WITH all_orgs AS (SELECT COALESCE( enabled, FALSE ) AS flag FROM config.global_flag WHERE name = 'opac.located_uri.act_as_copy') SELECT DISTINCT ON (id) * FROM ( SELECT acn.id, COALESCE(aou.name,aoud.name), acn.label_sortkey, evergreen.rank_ou(aou.id, $2, $3) AS pref_ou FROM asset.call_number acn INNER JOIN asset.uri_call_number_map auricnm ON acn.id = auricnm.call_number INNER JOIN asset.uri auri ON auri.id = auricnm.uri LEFT JOIN actor.org_unit_ancestors( COALESCE($3, $2) ) aou ON (acn.owning_lib = aou.id) LEFT JOIN actor.org_unit_descendants( COALESCE($3, $2) ) aoud ON (acn.owning_lib = aoud.id), all_orgs WHERE acn.record = ANY ($1) AND acn.deleted IS FALSE AND auri.active IS TRUE AND ((NOT all_orgs.flag AND aou.id IS NOT NULL) OR (all_orgs.flag AND COALESCE(aou.id,aoud.id) IS NOT NULL)) UNION SELECT acn.id, COALESCE(aou.name,aoud.name) AS name, acn.label_sortkey, evergreen.rank_ou(aou.id, $2, $3) AS pref_ou FROM asset.call_number acn INNER JOIN asset.uri_call_number_map auricnm ON acn.id = auricnm.call_number INNER JOIN asset.uri auri ON auri.id = auricnm.uri LEFT JOIN actor.org_unit_ancestors( $2 ) aou ON (acn.owning_lib = aou.id) LEFT JOIN actor.org_unit_descendants( $2 ) aoud ON (acn.owning_lib = aoud.id), all_orgs WHERE acn.record = ANY ($1) AND acn.deleted IS FALSE AND auri.active IS TRUE AND ((NOT all_orgs.flag AND aou.id IS NOT NULL) OR (all_orgs.flag AND COALESCE(aou.id,aoud.id) IS NOT NULL)))x ORDER BY id, pref_ou DESC;
Function: evergreen.located_uris_as_uris(pref_lib bigint, ouid integer, bibid integer)
Returns: SET OF uri
Language: SQL
/* Maps a bib directly to its scoped asset.uri's */ SELECT uri.* FROM evergreen.located_uris($1, $2, $3) located_uri JOIN asset.uri_call_number_map map ON (map.call_number = located_uri.id) JOIN asset.uri uri ON (uri.id = map.uri)
Function: evergreen.lowercase(text)
Returns: text
Language: PLPERLU
return lc(shift);
Function: evergreen.lpad_number_substrings(text, text, integer)
Returns: text
Language: PLPERLU
my $string = shift; # Source string my $pad = shift; # string to fill. Typically '0'. This should be a single character. my $len = shift; # length of resultant padded field $string =~ s/([0-9]+)/$pad x ($len - length($1)) . $1/eg; return $string;
Function: evergreen.maintain_901()
Returns: trigger
Language: PLPERLU
use strict; use MARC::Record; use MARC::File::XML (BinaryEncoding => 'UTF-8'); use MARC::Charset; use Encode; use Unicode::Normalize; MARC::Charset->assume_unicode(1); my $schema = $_TD->{table_schema}; my $marc = MARC::Record->new_from_xml($_TD->{new}{marc}); my @old901s = $marc->field('901'); $marc->delete_fields(@old901s); if ($schema eq 'biblio') { my $tcn_value = $_TD->{new}{tcn_value}; # Set TCN value to record ID? my $id_as_tcn = spi_exec_query(" SELECT enabled FROM config.global_flag WHERE name = 'cat.bib.use_id_for_tcn' "); if (($id_as_tcn->{processed}) && $id_as_tcn->{rows}[0]->{enabled} eq 't') { $tcn_value = $_TD->{new}{id}; $_TD->{new}{tcn_value} = $tcn_value; } my $new_901 = MARC::Field->new("901", " ", " ", "a" => $tcn_value, "b" => $_TD->{new}{tcn_source}, "c" => $_TD->{new}{id}, "t" => $schema ); if ($_TD->{new}{owner}) { $new_901->add_subfields("o" => $_TD->{new}{owner}); } if ($_TD->{new}{share_depth}) { $new_901->add_subfields("d" => $_TD->{new}{share_depth}); } if ($_TD->{new}{source}) { my $plan = spi_prepare(' SELECT source FROM config.bib_source WHERE id = $1 ', 'INTEGER'); my $source_name = spi_exec_prepared($plan, {limit => 1}, $_TD->{new}{source})->{rows}[0]{source}; spi_freeplan($plan); $new_901->add_subfields("s" => $source_name) if $source_name; } $marc->append_fields($new_901); } elsif ($schema eq 'authority') { my $new_901 = MARC::Field->new("901", " ", " ", "c" => $_TD->{new}{id}, "t" => $schema, ); $marc->append_fields($new_901); } elsif ($schema eq 'serial') { my $new_901 = MARC::Field->new("901", " ", " ", "c" => $_TD->{new}{id}, "t" => $schema, "o" => $_TD->{new}{owning_lib}, ); if ($_TD->{new}{record}) { $new_901->add_subfields("r" => $_TD->{new}{record}); } $marc->append_fields($new_901); } else { my $new_901 = MARC::Field->new("901", " ", " ", "c" => $_TD->{new}{id}, "t" => $schema, ); $marc->append_fields($new_901); } my $xml = $marc->as_xml_record(); $xml =~ s/\n//sgo; $xml =~ s/^<\?xml.+\?\s*>//go; $xml =~ s/>\s+</></go; $xml =~ s/\p{Cc}//go; # Embed a version of OpenILS::Application::AppUtils->entityize() # to avoid having to set PERL5LIB for PostgreSQL as well $xml = NFC($xml); # Convert raw ampersands to entities $xml =~ s/&(?!\S+;)/&/gso; # Convert Unicode characters to entities $xml =~ s/([\x{0080}-\x{fffd}])/sprintf('&#x%X;',ord($1))/sgoe; $xml =~ s/[\x00-\x1f]//go; $_TD->{new}{marc} = $xml; return "MODIFY";
Function: evergreen.maintain_control_numbers()
Returns: trigger
Language: PLPERLU
use strict; use MARC::Record; use MARC::File::XML (BinaryEncoding => 'UTF-8'); use MARC::Charset; use Encode; use Unicode::Normalize; MARC::Charset->assume_unicode(1); my $record = MARC::Record->new_from_xml($_TD->{new}{marc}); my $schema = $_TD->{table_schema}; my $rec_id = $_TD->{new}{id}; # Short-circuit if maintaining control numbers per MARC21 spec is not enabled my $enable = spi_exec_query("SELECT enabled FROM config.global_flag WHERE name = 'cat.maintain_control_numbers'"); if (!($enable->{processed}) or $enable->{rows}[0]->{enabled} eq 'f') { return; } # Get the control number identifier from an OU setting based on $_TD->{new}{owner} my $ou_cni = 'EVRGRN'; my $owner; if ($schema eq 'serial') { $owner = $_TD->{new}{owning_lib}; } else { # are.owner and bre.owner can be null, so fall back to the consortial setting $owner = $_TD->{new}{owner} || 1; } my $ous_rv = spi_exec_query("SELECT value FROM actor.org_unit_ancestor_setting('cat.marc_control_number_identifier', $owner)"); if ($ous_rv->{processed}) { $ou_cni = $ous_rv->{rows}[0]->{value}; $ou_cni =~ s/"//g; # Stupid VIM syntax highlighting" } else { # Fall back to the shortname of the OU if there was no OU setting $ous_rv = spi_exec_query("SELECT shortname FROM actor.org_unit WHERE id = $owner"); if ($ous_rv->{processed}) { $ou_cni = $ous_rv->{rows}[0]->{shortname}; } } my ($create, $munge) = (0, 0); my @scns = $record->field('035'); foreach my $id_field ('001', '003') { my $spec_value; my @controls = $record->field($id_field); if ($id_field eq '001') { $spec_value = $rec_id; } else { $spec_value = $ou_cni; } # Create the 001/003 if none exist if (scalar(@controls) == 1) { # Only one field; check to see if we need to munge it unless (grep $_->data() eq $spec_value, @controls) { $munge = 1; } } else { # Delete the other fields, as with more than 1 001/003 we do not know which 003/001 to match foreach my $control (@controls) { $record->delete_field($control); } $record->insert_fields_ordered(MARC::Field->new($id_field, $spec_value)); $create = 1; } } my $cn = $record->field('001')->data(); # Special handling of OCLC numbers, often found in records that lack 003 if ($cn =~ /^o(c[nm]|n)\d/) { $cn =~ s/^o(c[nm]|n)0*(\d+)/$2/; $record->field('003')->data('OCoLC'); $create = 0; } # Now, if we need to munge the 001, we will first push the existing 001/003 # into the 035; but if the record did not have one (and one only) 001 and 003 # to begin with, skip this process if ($munge and not $create) { my $scn = "(" . $record->field('003')->data() . ")" . $cn; # Do not create duplicate 035 fields unless (grep $_->subfield('a') eq $scn, @scns) { $record->insert_fields_ordered(MARC::Field->new('035', '', '', 'a' => $scn)); } } # Set the 001/003 and update the MARC if ($create or $munge) { $record->field('001')->data($rec_id); $record->field('003')->data($ou_cni); my $xml = $record->as_xml_record(); $xml =~ s/\n//sgo; $xml =~ s/^<\?xml.+\?\s*>//go; $xml =~ s/>\s+</></go; $xml =~ s/\p{Cc}//go; # Embed a version of OpenILS::Application::AppUtils->entityize() # to avoid having to set PERL5LIB for PostgreSQL as well $xml = NFC($xml); # Convert raw ampersands to entities $xml =~ s/&(?!\S+;)/&/gso; # Convert Unicode characters to entities $xml =~ s/([\x{0080}-\x{fffd}])/sprintf('&#x%X;',ord($1))/sgoe; $xml =~ s/[\x00-\x1f]//go; $_TD->{new}{marc} = $xml; return "MODIFY"; } return;
Function: evergreen.marc_to(xfrm text, marc text)
Returns: text
Language: SQL
SELECT evergreen.xml_pretty_print(xslt_process($1,xslt)::XML)::TEXT FROM config.xml_transform WHERE name = $2;
Function: evergreen.oils_i18n_code_tracking()
Returns: trigger
Language: PLPGSQL
BEGIN PERFORM oils_i18n_update_apply( OLD.code::TEXT, NEW.code::TEXT, TG_ARGV[0]::TEXT ); RETURN NEW; END;
Function: evergreen.oils_i18n_gettext(integer, text, text, text)
Returns: text
Language: SQL
SELECT $2;
Function: evergreen.oils_i18n_gettext(text, text, text, text)
Returns: text
Language: SQL
SELECT $2;
Function: evergreen.oils_i18n_id_tracking()
Returns: trigger
Language: PLPGSQL
BEGIN PERFORM oils_i18n_update_apply( OLD.id::TEXT, NEW.id::TEXT, TG_ARGV[0]::TEXT ); RETURN NEW; END;
Function: evergreen.oils_i18n_update_apply(hint text, new_ident text, old_ident text)
Returns: void
Language: PLPGSQL
BEGIN EXECUTE $$ UPDATE config.i18n_core SET identity_value = $$ || quote_literal(new_ident) || $$ WHERE fq_field LIKE '$$ || hint || $$.%' AND identity_value = $$ || quote_literal(old_ident) || $$::TEXT;$$; RETURN; END;
Function: evergreen.oils_i18n_xlate(raw_locale text, keyvalue text, identcol text, keycol text, keyclass text, keytable text)
Returns: text
Language: PLPGSQL
DECLARE locale TEXT := REGEXP_REPLACE( REGEXP_REPLACE( raw_locale, E'[;, ].+$', '' ), E'_', '-', 'g' ); language TEXT := REGEXP_REPLACE( locale, E'-.+$', '' ); result config.i18n_core%ROWTYPE; fallback TEXT; keyfield TEXT := keyclass || '.' || keycol; BEGIN -- Try the full locale SELECT * INTO result FROM config.i18n_core WHERE fq_field = keyfield AND identity_value = keyvalue AND translation = locale; -- Try just the language IF NOT FOUND THEN SELECT * INTO result FROM config.i18n_core WHERE fq_field = keyfield AND identity_value = keyvalue AND translation = language; END IF; -- Fall back to the string we passed in in the first place IF NOT FOUND THEN EXECUTE 'SELECT ' || keycol || ' FROM ' || keytable || ' WHERE ' || identcol || ' = ' || quote_literal(keyvalue) INTO fallback; RETURN fallback; END IF; RETURN result.string; END;
Function: evergreen.oils_json_to_text(text)
Returns: text
Language: PLPERLU
use JSON::XS; my $json = shift(); my $txt; eval { $txt = JSON::XS->new->allow_nonref->decode( $json ) }; return undef if ($@); return $txt
Function: evergreen.oils_text_as_bytea(text)
Returns: bytea
Language: SQL
SELECT CAST(REGEXP_REPLACE(UPPER($1), $$\\$$, $$\\\\$$, 'g') AS BYTEA);
Function: evergreen.oils_xpath(text, text)
Returns: text[]
Language: SQL
SELECT ARRAY_AGG( CASE WHEN strpos(x,'<') = 1 THEN -- It's an element node x ELSE -- it's text-ish evergreen.xml_famous5_to_text(x) END ) FROM UNNEST(XPATH( $1, $2::XML)::TEXT[]) x;
Function: evergreen.oils_xpath(text, text, text[])
Returns: text[]
Language: SQL
SELECT ARRAY_AGG( CASE WHEN strpos(x,'<') = 1 THEN -- It's an element node x ELSE -- it's text-ish evergreen.xml_famous5_to_text(x) END ) FROM UNNEST(XPATH( $1, $2::XML, $3 )::TEXT[]) x;
Function: evergreen.oils_xpath_string(text, text)
Returns: text
Language: SQL
SELECT oils_xpath_string( $1, $2, '{}'::TEXT[] );
Function: evergreen.oils_xpath_string(text, text, anyarray)
Returns: text
Language: SQL
SELECT oils_xpath_string( $1, $2, '', $3 );
Function: evergreen.oils_xpath_string(text, text, text)
Returns: text
Language: SQL
SELECT oils_xpath_string( $1, $2, $3, '{}'::TEXT[] );
Function: evergreen.oils_xpath_string(text, text, text, anyarray)
Returns: text
Language: SQL
SELECT ARRAY_TO_STRING( oils_xpath( $1 || CASE WHEN $1 ~ $re$/[^/[]*@[^]]+$$re$ OR $1 ~ $re$text\(\)$$re$ THEN '' ELSE '//text()' END, $2, $4 ), $3 );
Function: evergreen.oils_xpath_table(criteria text, xpaths text, relation_name text, document_field text, key text)
Returns: SET OF record
Language: PLPGSQL
DECLARE xpath_list TEXT[]; select_list TEXT[]; where_list TEXT[]; q TEXT; out_record RECORD; empty_test RECORD; BEGIN xpath_list := STRING_TO_ARRAY( xpaths, '|' ); select_list := ARRAY_APPEND( select_list, key || '::INT AS key' ); FOR i IN 1 .. ARRAY_UPPER(xpath_list,1) LOOP IF xpath_list[i] = 'null()' THEN select_list := ARRAY_APPEND( select_list, 'NULL::TEXT AS c_' || i ); ELSE select_list := ARRAY_APPEND( select_list, $sel$ unnest( COALESCE( NULLIF( oils_xpath( $sel$ || quote_literal( CASE WHEN xpath_list[i] ~ $re$/[^/[]*@[^/]+$$re$ OR xpath_list[i] ~ $re$text\(\)$$re$ THEN xpath_list[i] ELSE xpath_list[i] || '//text()' END ) || $sel$, $sel$ || document_field || $sel$ ), '{}'::TEXT[] ), '{NULL}'::TEXT[] ) ) AS c_$sel$ || i ); where_list := ARRAY_APPEND( where_list, 'c_' || i || ' IS NOT NULL' ); END IF; END LOOP; q := $q$ SELECT * FROM ( SELECT $q$ || ARRAY_TO_STRING( select_list, ', ' ) || $q$ FROM $q$ || relation_name || $q$ WHERE ($q$ || criteria || $q$) )x WHERE $q$ || ARRAY_TO_STRING( where_list, ' OR ' ); -- RAISE NOTICE 'query: %', q; FOR out_record IN EXECUTE q LOOP RETURN NEXT out_record; END LOOP; RETURN; END;
Function: evergreen.oils_xpath_tag_to_table(xpaths text, tag text, marc text[])
Returns: SET OF record
Language: PLPGSQL
-- This function currently populates columns with the FIRST matching value -- of each XPATH. It would be reasonable to add a 'return_arrays' option -- where each column is an array of all matching values for each path, but -- that remains as a TODO DECLARE field RECORD; output RECORD; select_list TEXT[]; from_list TEXT[]; q TEXT; BEGIN -- setup query select FOR i IN 1 .. ARRAY_UPPER(xpaths,1) LOOP IF xpaths[i] = 'null()' THEN select_list := ARRAY_APPEND(select_list, 'NULL::TEXT AS c_' || i ); ELSE select_list := ARRAY_APPEND(select_list, '(oils_xpath(' || quote_literal( CASE WHEN xpaths[i] ~ $re$/[^/[]*@[^/]+$$re$ -- attribute OR xpaths[i] ~ $re$text\(\)$$re$ THEN xpaths[i] ELSE xpaths[i] || '//text()' END ) || ', field_marc))[1] AS cl_' || i); -- hardcoded to first value for each path END IF; END LOOP; -- run query over tag set q := 'SELECT ' || ARRAY_TO_STRING(select_list, ',') || ' FROM UNNEST(oils_xpath(' || quote_literal('//*[@tag="' || tag || '"]') || ', ' || quote_literal(marc) || ')) AS field_marc;'; --RAISE NOTICE '%', q; RETURN QUERY EXECUTE q; END;
Function: evergreen.oils_xslt_process(text, text)
Returns: text
Language: PLPERLU
use strict; use XML::LibXSLT; use XML::LibXML; my $doc = shift; my $xslt = shift; # The following approach uses the older XML::LibXML 1.69 / XML::LibXSLT 1.68 # methods of parsing XML documents and stylesheets, in the hopes of broader # compatibility with distributions my $parser = $_SHARED{'_xslt_process'}{parsers}{xml} || XML::LibXML->new(); # Cache the XML parser, if we do not already have one $_SHARED{'_xslt_process'}{parsers}{xml} = $parser unless ($_SHARED{'_xslt_process'}{parsers}{xml}); my $xslt_parser = $_SHARED{'_xslt_process'}{parsers}{xslt} || XML::LibXSLT->new(); # Cache the XSLT processor, if we do not already have one $_SHARED{'_xslt_process'}{parsers}{xslt} = $xslt_parser unless ($_SHARED{'_xslt_process'}{parsers}{xslt}); my $stylesheet = $_SHARED{'_xslt_process'}{stylesheets}{$xslt} || $xslt_parser->parse_stylesheet( $parser->parse_string($xslt) ); $_SHARED{'_xslt_process'}{stylesheets}{$xslt} = $stylesheet unless ($_SHARED{'_xslt_process'}{stylesheets}{$xslt}); return $stylesheet->output_as_chars( $stylesheet->transform( $parser->parse_string($doc) ) );
Function: evergreen.org_top()
Returns: org_unit
Language: SQL
SELECT * FROM actor.org_unit WHERE parent_ou IS NULL LIMIT 1;
Function: evergreen.ous_change_log()
Returns: trigger
Language: PLPGSQL
DECLARE original TEXT; BEGIN -- Check for which setting is being updated, and log it. SELECT INTO original value FROM actor.org_unit_setting WHERE name = NEW.name AND org_unit = NEW.org_unit; INSERT INTO config.org_unit_setting_type_log (org,original_value,new_value,field_name) VALUES (NEW.org_unit, original, NEW.value, NEW.name); RETURN NEW; END;
Function: evergreen.ous_delete_log()
Returns: trigger
Language: PLPGSQL
DECLARE original TEXT; BEGIN -- Check for which setting is being updated, and log it. SELECT INTO original value FROM actor.org_unit_setting WHERE name = OLD.name AND org_unit = OLD.org_unit; INSERT INTO config.org_unit_setting_type_log (org,original_value,new_value,field_name) VALUES (OLD.org_unit, original, 'null', OLD.name); RETURN OLD; END;
Function: evergreen.pg_statistics(frequency text, element text)
Returns: SET OF record
Language: PLPGSQL
BEGIN -- This query will die on PG < 9.2, but the function can be created. We just won't use it where we can't. RETURN QUERY SELECT e, f FROM (SELECT ROW_NUMBER() OVER (), (f * 100)::INT AS f FROM (SELECT UNNEST(most_common_elem_freqs) AS f FROM pg_stats WHERE tablename = tab AND attname = col )x ) AS f JOIN (SELECT ROW_NUMBER() OVER (), e FROM (SELECT UNNEST(most_common_elems::text::text[]) AS e FROM pg_stats WHERE tablename = tab AND attname = col )y ) AS elems USING (row_number); END;
Function: evergreen.protect_reserved_rows_from_delete()
Returns: trigger
Language: PLPGSQL
BEGIN IF OLD.id < TG_ARGV[0]::INT THEN RAISE EXCEPTION 'Cannot delete row with reserved ID %', OLD.id; END IF; RETURN OLD; END
Function: evergreen.query_int_wrapper(integer[], text)
Returns: boolean
Language: PLPGSQL
BEGIN RETURN $1 @@ $2::query_int; END;
Function: evergreen.qwerty_keyboard_distance(b text, a text)
Returns: numeric
Language: PLPERLU
use String::KeyboardDistance qw(:all); return qwerty_keyboard_distance(@_);
Function: evergreen.qwerty_keyboard_distance_match(b text, a text)
Returns: numeric
Language: PLPERLU
use String::KeyboardDistance qw(:all); return qwerty_keyboard_distance_match(@_);
Function: evergreen.rank_cp(copy asset.copy)
Returns: integer
Language: PLPGSQL
DECLARE rank INT; BEGIN WITH totally_available AS ( SELECT id, 0 AS avail_rank FROM config.copy_status WHERE opac_visible IS TRUE AND copy_active IS TRUE AND id != 1 -- "Checked out" ), almost_available AS ( SELECT id, 10 AS avail_rank FROM config.copy_status WHERE holdable IS TRUE AND opac_visible IS TRUE AND copy_active IS FALSE OR id = 1 -- "Checked out" ) SELECT COALESCE( CASE WHEN NOT copy.opac_visible THEN 100 END, (SELECT avail_rank FROM totally_available WHERE copy.status IN (id)), CASE WHEN copy.holdable THEN (SELECT avail_rank FROM almost_available WHERE copy.status IN (id)) END, 100 ) INTO rank; RETURN rank; END;
Function: evergreen.rank_cp(copy_id bigint)
Returns: integer
Language: PLPGSQL
DECLARE copy asset.copy%ROWTYPE; BEGIN SELECT * INTO copy FROM asset.copy WHERE id = copy_id; RETURN evergreen.rank_cp(copy); END;
Function: evergreen.rank_ou(plon integer, plat integer, pref_lib integer, search_lib double precision, lib double precision)
Returns: integer
Language: SQL
SELECT COALESCE( -- lib matches search_lib (SELECT CASE WHEN $1 = $2 THEN -20000 END), -- lib matches pref_lib (SELECT CASE WHEN $1 = $3 THEN -10000 END), -- pref_lib is a child of search_lib and lib is a child of pref lib. -- For example, searching CONS, pref lib is SYS1, -- copies at BR1 and BR2 sort to the front. (SELECT distance - 5000 FROM actor.org_unit_descendants_distance($3) WHERE id = $1 AND $3 IN ( SELECT id FROM actor.org_unit_descendants($2))), -- lib is a child of search_lib (SELECT distance FROM actor.org_unit_descendants_distance($2) WHERE id = $1), -- all others pay cash 1000 ) + ((SELECT CASE WHEN addr.latitude IS NULL THEN 0 ELSE -20038 END) + (earth_distance( -- shortest GC distance is returned, only half the circumfrence is needed ll_to_earth( COALESCE(addr.latitude,plat), -- if the org has no coords, we just COALESCE(addr.longitude,plon) -- force 0 distance and let the above tie-break ),ll_to_earth(plat,plon) ) / 1000)::INT ) -- earth_distance is in meters, convert to kilometers and subtract from largest distance FROM actor.org_unit org LEFT JOIN actor.org_address addr ON (org.billing_address = addr.id) WHERE org.id = $1;
Function: evergreen.rank_ou(pref_lib integer, search_lib integer, lib integer)
Returns: integer
Language: SQL
SELECT COALESCE( -- lib matches search_lib (SELECT CASE WHEN $1 = $2 THEN -20000 END), -- lib matches pref_lib (SELECT CASE WHEN $1 = $3 THEN -10000 END), -- pref_lib is a child of search_lib and lib is a child of pref lib. -- For example, searching CONS, pref lib is SYS1, -- copies at BR1 and BR2 sort to the front. (SELECT distance - 5000 FROM actor.org_unit_descendants_distance($3) WHERE id = $1 AND $3 IN ( SELECT id FROM actor.org_unit_descendants($2))), -- lib is a child of search_lib (SELECT distance FROM actor.org_unit_descendants_distance($2) WHERE id = $1), -- all others pay cash 1000 );
Function: evergreen.ranked_volumes(rank bigint, label_sortkey integer, name integer, id public.hstore, includes public.hstore, pref_lib integer, soffset text[])
Returns: SET OF record
Language: SQL
SELECT * FROM evergreen.ranked_volumes(ARRAY[$1],$2,$3,$4,$5,$6,$7)
Function: evergreen.ranked_volumes(rank bigint[], label_sortkey integer, name integer, id public.hstore, includes public.hstore, pref_lib integer, soffset text[])
Returns: SET OF record
Language: SQL
WITH RECURSIVE ou_depth AS ( SELECT COALESCE( $3, ( SELECT depth FROM actor.org_unit_type aout INNER JOIN actor.org_unit ou ON ou_type = aout.id WHERE ou.id = $2 ) ) AS depth ), descendant_depth AS ( SELECT ou.id, ou.parent_ou, out.depth FROM actor.org_unit ou JOIN actor.org_unit_type out ON (out.id = ou.ou_type) JOIN anscestor_depth ad ON (ad.id = ou.id), ou_depth WHERE ad.depth = ou_depth.depth UNION ALL SELECT ou.id, ou.parent_ou, out.depth FROM actor.org_unit ou JOIN actor.org_unit_type out ON (out.id = ou.ou_type) JOIN descendant_depth ot ON (ot.id = ou.parent_ou) ), anscestor_depth AS ( SELECT ou.id, ou.parent_ou, out.depth FROM actor.org_unit ou JOIN actor.org_unit_type out ON (out.id = ou.ou_type) WHERE ou.id = $2 UNION ALL SELECT ou.id, ou.parent_ou, out.depth FROM actor.org_unit ou JOIN actor.org_unit_type out ON (out.id = ou.ou_type) JOIN anscestor_depth ot ON (ot.parent_ou = ou.id) ), descendants as ( SELECT ou.* FROM actor.org_unit ou JOIN descendant_depth USING (id) ) SELECT ua.id, ua.name, ua.label_sortkey, MIN(ua.rank) AS rank FROM ( SELECT acn.id, owning_lib.name, acn.label_sortkey, evergreen.rank_cp(acp), RANK() OVER w FROM asset.call_number acn JOIN asset.copy acp ON (acn.id = acp.call_number) JOIN descendants AS aou ON (acp.circ_lib = aou.id) JOIN actor.org_unit AS owning_lib ON (acn.owning_lib = owning_lib.id) WHERE acn.record = ANY ($1) AND acn.deleted IS FALSE AND acp.deleted IS FALSE AND CASE WHEN ('exclude_invisible_acn' = ANY($7)) THEN EXISTS ( WITH basevm AS (SELECT c_attrs FROM asset.patron_default_visibility_mask()), circvm AS (SELECT search.calculate_visibility_attribute_test('circ_lib', ARRAY[acp.circ_lib]) AS mask) SELECT 1 FROM basevm, circvm, asset.copy_vis_attr_cache acvac WHERE acvac.vis_attr_vector @@ (basevm.c_attrs || '&' || circvm.mask)::query_int AND acvac.target_copy = acp.id AND acvac.record = acn.record ) ELSE TRUE END GROUP BY acn.id, evergreen.rank_cp(acp), owning_lib.name, acn.label_sortkey, aou.id WINDOW w AS ( ORDER BY COALESCE( CASE WHEN aou.id = $2 THEN -20000 END, CASE WHEN aou.id = $6 THEN -10000 END, (SELECT distance - 5000 FROM actor.org_unit_descendants_distance($6) as x WHERE x.id = aou.id AND $6 IN ( SELECT q.id FROM actor.org_unit_descendants($2) as q)), (SELECT e.distance FROM actor.org_unit_descendants_distance($2) as e WHERE e.id = aou.id), 1000 ), evergreen.rank_cp(acp) ) ) AS ua GROUP BY ua.id, ua.name, ua.label_sortkey ORDER BY rank, ua.name, ua.label_sortkey LIMIT ($4 -> 'acn')::INT OFFSET ($5 -> 'acn')::INT;
Function: evergreen.regexp_split_to_array(text, text)
Returns: text[]
Language: PLPERLU
return encode_array_literal([split $_[1], $_[0]]);
Function: evergreen.rel_bump(mults text[], bumps text, value text[], terms numeric[])
Returns: numeric
Language: PLPERLU
use strict; my ($terms,$value,$bumps,$mults) = @_; my $retval = 1; for (my $id = 0; $id < @$bumps; $id++) { if ($bumps->[$id] eq 'first_word') { $retval *= $mults->[$id] if ($value =~ /^$terms->[0]/); } elsif ($bumps->[$id] eq 'full_match') { my $fullmatch = join(' ', @$terms); $retval *= $mults->[$id] if ($value =~ /^$fullmatch$/); } elsif ($bumps->[$id] eq 'word_order') { my $wordorder = join('.*', @$terms); $retval *= $mults->[$id] if ($value =~ /$wordorder/); } } return $retval;
Function: evergreen.tableoid2name(oid)
Returns: text
Language: PLPGSQL
BEGIN RETURN $1::regclass; END;
Function: evergreen.text_array_merge_unique(text[], text[])
Returns: text[]
Language: SQL
SELECT NULLIF(ARRAY( SELECT * FROM UNNEST($1) x UNION SELECT * FROM UNNEST($2) y ),'{}');
Function: evergreen.unaccent_and_squash(arg text)
Returns: text
Language: PLPGSQL
BEGIN RETURN evergreen.lowercase(public.unaccent('public.unaccent', regexp_replace(arg, '[\s[:punct:]]','','g'))); END;
Function: evergreen.upgrade_deps_block_check(my_applied_to text, my_db_patch text)
Returns: boolean
Language: PLPGSQL
DECLARE deprecates TEXT; supersedes TEXT; BEGIN IF NOT evergreen.upgrade_verify_no_dep_conflicts( my_db_patch ) THEN SELECT STRING_AGG(patch, ', ') INTO deprecates FROM evergreen.upgrade_list_applied_deprecates(my_db_patch); SELECT STRING_AGG(patch, ', ') INTO supersedes FROM evergreen.upgrade_list_applied_supersedes(my_db_patch); RAISE EXCEPTION ' Upgrade script % can not be applied: applied deprecated scripts % applied superseded scripts % deprecated by % superseded by %', my_db_patch, (SELECT ARRAY_AGG(patch) FROM evergreen.upgrade_list_applied_deprecates(my_db_patch)), (SELECT ARRAY_AGG(patch) FROM evergreen.upgrade_list_applied_supersedes(my_db_patch)), evergreen.upgrade_list_applied_deprecated(my_db_patch), evergreen.upgrade_list_applied_superseded(my_db_patch); END IF; INSERT INTO config.upgrade_log (version, applied_to) VALUES (my_db_patch, my_applied_to); RETURN TRUE; END;
Function: evergreen.upgrade_list_applied_deprecated(my_db_patch text)
Returns: SET OF text
Language: SQL
SELECT db_patch FROM config.db_patch_dependencies WHERE ARRAY[$1]::TEXT[] && deprecates
Function: evergreen.upgrade_list_applied_deprecates(my_db_patch text)
Returns: SET OF patch
Language: SQL
SELECT DISTINCT l.version FROM config.upgrade_log l JOIN config.db_patch_dependencies d ON (l.version = ANY(d.deprecates)) WHERE d.db_patch = $1
Function: evergreen.upgrade_list_applied_superseded(my_db_patch text)
Returns: SET OF text
Language: SQL
SELECT db_patch FROM config.db_patch_dependencies WHERE ARRAY[$1]::TEXT[] && supersedes
Function: evergreen.upgrade_list_applied_supersedes(my_db_patch text)
Returns: SET OF patch
Language: SQL
SELECT DISTINCT l.version FROM config.upgrade_log l JOIN config.db_patch_dependencies d ON (l.version = ANY(d.supersedes)) WHERE d.db_patch = $1
Function: evergreen.upgrade_verify_no_dep_conflicts(my_db_patch text)
Returns: boolean
Language: SQL
SELECT COUNT(*) = 0 FROM (SELECT * FROM evergreen.upgrade_list_applied_deprecates( $1 ) UNION SELECT * FROM evergreen.upgrade_list_applied_supersedes( $1 ) UNION SELECT * FROM evergreen.upgrade_list_applied_deprecated( $1 ) UNION SELECT * FROM evergreen.upgrade_list_applied_superseded( $1 ))x
Function: evergreen.uppercase(text)
Returns: text
Language: PLPERLU
return uc(shift);
Function: evergreen.vandelay_import_item_imported_as_inh_fkey()
Returns: trigger
Language: PLPGSQL
BEGIN IF NEW.imported_as IS NULL THEN RETURN NEW; END IF; PERFORM 1 FROM asset.copy WHERE id = NEW.imported_as; IF NOT FOUND THEN RAISE foreign_key_violation USING MESSAGE = FORMAT( $$Referenced asset.copy id not found, imported_as:%s$$, NEW.imported_as ); END IF; RETURN NEW; END;
Function: evergreen.xml_escape(str text)
Returns: text
Language: SQL
SELECT REPLACE(REPLACE(REPLACE($1, '&', '&'), '<', '<'), '>', '>');
Function: evergreen.xml_famous5_to_text(text)
Returns: text
Language: SQL
SELECT REPLACE( REPLACE( REPLACE( REPLACE( REPLACE( $1, '<', '<'), '>', '>' ), ''', $$'$$ ), -- ' ... vim '"', '"' ), '&', '&' );
Function: evergreen.xml_pretty_print(input xml)
Returns: xml
Language: SQL
Simple pretty printer for XML, as written by Andrew Dunstan at http://goo.gl/zBHIk
SELECT xslt_process($1::text, $$<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet> $$::text)::XML
Function: evergreen.z3950_attr_name_is_valid()
Returns: trigger
Language: PLPGSQL
Used by a config.z3950_index_field_map constraint trigger to verify z3950_attr_type maps.
BEGIN PERFORM * FROM config.z3950_attr WHERE name = NEW.z3950_attr_type; IF FOUND THEN RETURN NULL; END IF; RAISE EXCEPTION '% is not a valid Z39.50 attribute type', NEW.z3950_attr_type; END;
Schema extend_reporter
View: extend_reporter.copy_count_per_org
F-Key | Name | Type | Description |
---|---|---|---|
bibid | bigint | ||
circ_lib | integer | ||
owning_lib | integer | ||
last_edit_time | timestamp with time zone | ||
has_only_deleted_copies | integer | ||
deleted_count | bigint | ||
visible_count | bigint | ||
total_count | bigint |
SELECT acn.record AS bibid , ac.circ_lib , acn.owning_lib , max (ac.edit_date) AS last_edit_time , min ( (ac.deleted)::integer ) AS has_only_deleted_copies , count ( CASE WHEN ac.deleted THEN ac.id ELSE NULL::bigint END) AS deleted_count , count ( CASE WHEN (NOT ac.deleted) THEN ac.id ELSE NULL::bigint END ) AS visible_count , count (*) AS total_count FROM asset.call_number acn , asset.copy ac WHERE (ac.call_number = acn.id) GROUP BY acn.record , acn.owning_lib , ac.circ_lib;
Index - Schema extend_reporter
View: extend_reporter.full_circ_count
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
circ_count | bigint |
SELECT cp.id , ( (COALESCE ( ( SELECT legacy_circ_count.circ_count FROM extend_reporter.legacy_circ_count WHERE (legacy_circ_count.id = cp.id) ) , 0 ) + ( SELECT count (*) AS count FROM action.circulation WHERE (circulation.target_copy = cp.id) ) ) + ( SELECT count (*) AS count FROM action.aged_circulation WHERE (aged_circulation.target_copy = cp.id) ) ) AS circ_count FROM asset.copy cp;
Index - Schema extend_reporter
View: extend_reporter.global_bibs_by_holding_update
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
holding_update | timestamp with time zone | ||
update_type | text |
SELECT DISTINCT ON (x.id) x.id , x.holding_update , x.update_type FROM ( SELECT b.id , last (cp.create_date) AS holding_update , 'add'::text AS update_type FROM ( (biblio.record_entry b JOIN asset.call_number cn ON ( (cn.record = b.id) ) ) JOIN asset.copy cp ON ( (cp.call_number = cn.id) ) ) WHERE ( (NOT cp.deleted) AND (b.id > 0) ) GROUP BY b.id UNION SELECT b.id , last (cp.edit_date) AS holding_update , 'delete'::text AS update_type FROM ( (biblio.record_entry b JOIN asset.call_number cn ON ( (cn.record = b.id) ) ) JOIN asset.copy cp ON ( (cp.call_number = cn.id) ) ) WHERE (cp.deleted AND (b.id > 0) ) GROUP BY b.id ) x ORDER BY x.id , x.holding_update;
Index - Schema extend_reporter
Table: extend_reporter.legacy_circ_count
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY | |
circ_count | integer | NOT NULL |
Index - Schema extend_reporter
Schema metabib
Table: metabib.author_field_entry
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
biblio.record_entry.id | source | bigint | NOT NULL |
config.metabib_field.id | field | integer | NOT NULL |
value | text | NOT NULL | |
index_vector | tsvector | NOT NULL |
Table: metabib.browse_entry
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
value | text | UNIQUE#1 | |
index_vector | tsvector | ||
sort_value | text | UNIQUE#1 NOT NULL |
Tables referencing this one via Foreign Key Constraints:
browse_entry_sort_value_idx sort_value metabib_browse_entry_index_vector_idx index_vectorTable: metabib.browse_entry_def_map
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
metabib.browse_entry.id | entry | bigint | |
config.metabib_field.id | def | integer | |
biblio.record_entry.id | source | bigint | |
authority.record_entry.id | authority | bigint |
Table: metabib.browse_entry_simple_heading_map
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
metabib.browse_entry.id | entry | bigint | |
authority.simple_heading.id | simple_heading | bigint |
View: metabib.combined_all_field_entry
F-Key | Name | Type | Description |
---|---|---|---|
record | bigint | ||
metabib_field | integer | ||
index_vector | tsvector |
SELECT combined_title_field_entry.record , combined_title_field_entry.metabib_field , combined_title_field_entry.index_vector FROM metabib.combined_title_field_entry UNION ALL SELECT combined_author_field_entry.record , combined_author_field_entry.metabib_field , combined_author_field_entry.index_vector FROM metabib.combined_author_field_entry UNION ALL SELECT combined_subject_field_entry.record , combined_subject_field_entry.metabib_field , combined_subject_field_entry.index_vector FROM metabib.combined_subject_field_entry UNION ALL SELECT combined_keyword_field_entry.record , combined_keyword_field_entry.metabib_field , combined_keyword_field_entry.index_vector FROM metabib.combined_keyword_field_entry UNION ALL SELECT combined_identifier_field_entry.record , combined_identifier_field_entry.metabib_field , combined_identifier_field_entry.index_vector FROM metabib.combined_identifier_field_entry UNION ALL SELECT combined_series_field_entry.record , combined_series_field_entry.metabib_field , combined_series_field_entry.index_vector FROM metabib.combined_series_field_entry;
Table: metabib.combined_author_field_entry
F-Key | Name | Type | Description |
---|---|---|---|
record | bigint | NOT NULL | |
metabib_field | integer | ||
index_vector | tsvector | NOT NULL |
Table: metabib.combined_identifier_field_entry
F-Key | Name | Type | Description |
---|---|---|---|
record | bigint | NOT NULL | |
metabib_field | integer | ||
index_vector | tsvector | NOT NULL |
Table: metabib.combined_keyword_field_entry
F-Key | Name | Type | Description |
---|---|---|---|
record | bigint | NOT NULL | |
metabib_field | integer | ||
index_vector | tsvector | NOT NULL |
Table: metabib.combined_series_field_entry
F-Key | Name | Type | Description |
---|---|---|---|
record | bigint | NOT NULL | |
metabib_field | integer | ||
index_vector | tsvector | NOT NULL |
Table: metabib.combined_subject_field_entry
F-Key | Name | Type | Description |
---|---|---|---|
record | bigint | NOT NULL | |
metabib_field | integer | ||
index_vector | tsvector | NOT NULL |
Table: metabib.combined_title_field_entry
F-Key | Name | Type | Description |
---|---|---|---|
record | bigint | NOT NULL | |
metabib_field | integer | ||
index_vector | tsvector | NOT NULL |
View: metabib.composite_attr_id_map
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
attr | text | ||
value | text |
SELECT c.id , c.ctype AS attr , c.code AS value FROM (config.coded_value_map c JOIN config.record_attr_definition d ON ( ( (d.name = c.ctype) AND d.composite ) ) );
View: metabib.compressed_display_entry
F-Key | Name | Type | Description |
---|---|---|---|
source | bigint | ||
name | text | ||
multi | boolean | ||
label | text | ||
field | integer | ||
value | json |
SELECT flat_display_entry.source , flat_display_entry.name , flat_display_entry.multi , flat_display_entry.label , flat_display_entry.field , CASE WHEN flat_display_entry.multi THEN to_json (array_agg (flat_display_entry.value) ) ELSE to_json (min (flat_display_entry.value) ) END AS value FROM metabib.flat_display_entry GROUP BY flat_display_entry.source , flat_display_entry.name , flat_display_entry.multi , flat_display_entry.label , flat_display_entry.field;
Table: metabib.display_entry
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
source | bigint | NOT NULL | |
field | integer | NOT NULL | |
value | text | NOT NULL |
Table: metabib.facet_entry
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
source | bigint | NOT NULL | |
field | integer | NOT NULL | |
value | text | NOT NULL |
View: metabib.flat_display_entry
F-Key | Name | Type | Description |
---|---|---|---|
source | bigint | ||
name | text | ||
multi | boolean | ||
label | text | ||
field | integer | ||
value | text |
SELECT mde.source , cdfm.name , cdfm.multi , cmf.label , cmf.id AS field , mde.value FROM ( (metabib.display_entry mde JOIN config.metabib_field cmf ON ( (cmf.id = mde.field) ) ) JOIN config.display_field_map cdfm ON ( (cdfm.field = mde.field) ) );
View: metabib.full_attr_id_map
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
attr | text | ||
value | text |
SELECT record_attr_id_map.id , record_attr_id_map.attr , record_attr_id_map.value FROM metabib.record_attr_id_map UNION SELECT composite_attr_id_map.id , composite_attr_id_map.attr , composite_attr_id_map.value FROM metabib.composite_attr_id_map;
View: metabib.full_rec
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
record | bigint | ||
tag | character(3) | ||
ind1 | text | ||
ind2 | text | ||
subfield | text | ||
value | text | ||
index_vector | tsvector |
SELECT real_full_rec.id , real_full_rec.record , real_full_rec.tag , real_full_rec.ind1 , real_full_rec.ind2 , real_full_rec.subfield , "substring" (real_full_rec.value , 1 , 1024 ) AS value , real_full_rec.index_vector FROM metabib.real_full_rec;
Table: metabib.identifier_field_entry
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
biblio.record_entry.id | source | bigint | NOT NULL |
config.metabib_field.id | field | integer | NOT NULL |
value | text | NOT NULL | |
index_vector | tsvector | NOT NULL |
Table: metabib.keyword_field_entry
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
biblio.record_entry.id | source | bigint | NOT NULL |
config.metabib_field.id | field | integer | NOT NULL |
value | text | NOT NULL | |
index_vector | tsvector | NOT NULL |
Table: metabib.metarecord
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
fingerprint | text | NOT NULL | |
biblio.record_entry.id | master_record | bigint | |
mods | text |
Tables referencing this one via Foreign Key Constraints:
metabib_metarecord_fingerprint_idx fingerprint metabib_metarecord_master_record_idx master_recordTable: metabib.metarecord_source_map
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
metabib.metarecord.id | metarecord | bigint | NOT NULL |
biblio.record_entry.id | source | bigint | NOT NULL |
Table: metabib.real_full_rec
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY DEFAULT nextval('metabib.full_rec_id_seq'::regclass) | |
biblio.record_entry.id | record | bigint | NOT NULL |
tag | character(3) | NOT NULL | |
ind1 | text | ||
ind2 | text | ||
subfield | text | ||
value | text | NOT NULL | |
index_vector | tsvector | NOT NULL |
View: metabib.rec_descriptor
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
record | bigint | ||
item_type | text | ||
item_form | text | ||
bib_level | text | ||
control_type | text | ||
char_encoding | text | ||
enc_level | text | ||
audience | text | ||
lit_form | text | ||
type_mat | text | ||
cat_form | text | ||
pub_status | text | ||
item_lang | text | ||
vr_format | text | ||
date1 | text | ||
date2 | text |
SELECT record_attr.id , record_attr.id AS record , (populate_record (NULL::metabib.rec_desc_type , record_attr.attrs ) ).item_type AS item_type , (populate_record (NULL::metabib.rec_desc_type , record_attr.attrs ) ).item_form AS item_form , (populate_record (NULL::metabib.rec_desc_type , record_attr.attrs ) ).bib_level AS bib_level , (populate_record (NULL::metabib.rec_desc_type , record_attr.attrs ) ).control_type AS control_type , (populate_record (NULL::metabib.rec_desc_type , record_attr.attrs ) ).char_encoding AS char_encoding , (populate_record (NULL::metabib.rec_desc_type , record_attr.attrs ) ).enc_level AS enc_level , (populate_record (NULL::metabib.rec_desc_type , record_attr.attrs ) ).audience AS audience , (populate_record (NULL::metabib.rec_desc_type , record_attr.attrs ) ).lit_form AS lit_form , (populate_record (NULL::metabib.rec_desc_type , record_attr.attrs ) ).type_mat AS type_mat , (populate_record (NULL::metabib.rec_desc_type , record_attr.attrs ) ).cat_form AS cat_form , (populate_record (NULL::metabib.rec_desc_type , record_attr.attrs ) ).pub_status AS pub_status , (populate_record (NULL::metabib.rec_desc_type , record_attr.attrs ) ).item_lang AS item_lang , (populate_record (NULL::metabib.rec_desc_type , record_attr.attrs ) ).vr_format AS vr_format , (populate_record (NULL::metabib.rec_desc_type , record_attr.attrs ) ).date1 AS date1 , (populate_record (NULL::metabib.rec_desc_type , record_attr.attrs ) ).date2 AS date2 FROM metabib.record_attr;
View: metabib.record_attr
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
attrs | hstore |
SELECT record_attr_flat.id , hstore (array_agg (record_attr_flat.attr) , array_agg (record_attr_flat.value) ) AS attrs FROM metabib.record_attr_flat WHERE (record_attr_flat.attr IS NOT NULL) GROUP BY record_attr_flat.id;
View: metabib.record_attr_flat
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
attr | text | ||
value | text |
SELECT v.source AS id , m.attr , m.value FROM (metabib.record_attr_vector_list v LEFT JOIN metabib.uncontrolled_record_attr_value m ON ( (m.id = ANY (v.vlist) ) ) ) UNION SELECT v.source AS id , c.ctype AS attr , c.code AS value FROM (metabib.record_attr_vector_list v LEFT JOIN config.coded_value_map c ON ( (c.id = ANY (v.vlist) ) ) );
View: metabib.record_attr_id_map
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
attr | text | ||
value | text |
SELECT uncontrolled_record_attr_value.id , uncontrolled_record_attr_value.attr , uncontrolled_record_attr_value.value FROM metabib.uncontrolled_record_attr_value UNION SELECT c.id , c.ctype AS attr , c.code AS value FROM (config.coded_value_map c JOIN config.record_attr_definition d ON ( ( (d.name = c.ctype) AND (NOT d.composite) ) ) );
Table: metabib.record_attr_vector_list
F-Key | Name | Type | Description |
---|---|---|---|
biblio.record_entry.id | source | bigint | PRIMARY KEY |
vlist | integer[] | NOT NULL |
Table: metabib.record_sorter
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
biblio.record_entry.id | source | bigint | NOT NULL |
config.record_attr_definition.name | attr | text | NOT NULL |
value | text | NOT NULL |
Table: metabib.series_field_entry
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
biblio.record_entry.id | source | bigint | NOT NULL |
config.metabib_field.id | field | integer | NOT NULL |
value | text | NOT NULL | |
index_vector | tsvector | NOT NULL |
Table: metabib.subject_field_entry
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
biblio.record_entry.id | source | bigint | NOT NULL |
config.metabib_field.id | field | integer | NOT NULL |
value | text | NOT NULL | |
index_vector | tsvector | NOT NULL |
Table: metabib.title_field_entry
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
biblio.record_entry.id | source | bigint | NOT NULL |
config.metabib_field.id | field | integer | NOT NULL |
value | text | NOT NULL | |
index_vector | tsvector | NOT NULL |
Table: metabib.uncontrolled_record_attr_value
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY DEFAULT nextval('metabib.uncontrolled_record_attr_value_id_seq'::regclass) | |
config.record_attr_definition.name | attr | text | NOT NULL |
value | text | NOT NULL |
View: metabib.wide_display_entry
F-Key | Name | Type | Description |
---|---|---|---|
source | bigint | ||
title | text | ||
author | text | ||
subject_geographic | text | ||
subject_name | text | ||
subject_temporal | text | ||
subject_topic | text | ||
creators | text | ||
isbn | text | ||
issn | text | ||
upc | text | ||
tcn | text | ||
edition | text | ||
physical_description | text | ||
publisher | text | ||
series_title | text | ||
abstract | text | ||
toc | text | ||
pubdate | text | ||
type_of_resource | text |
SELECT bre.id AS source , (COALESCE (mcde_title.value ,'null'::json ) )::text AS title , (COALESCE (mcde_author.value ,'null'::json ) )::text AS author , (COALESCE (mcde_subject_geographic.value ,'null'::json ) )::text AS subject_geographic , (COALESCE (mcde_subject_name.value ,'null'::json ) )::text AS subject_name , (COALESCE (mcde_subject_temporal.value ,'null'::json ) )::text AS subject_temporal , (COALESCE (mcde_subject_topic.value ,'null'::json ) )::text AS subject_topic , (COALESCE (mcde_creators.value ,'null'::json ) )::text AS creators , (COALESCE (mcde_isbn.value ,'null'::json ) )::text AS isbn , (COALESCE (mcde_issn.value ,'null'::json ) )::text AS issn , (COALESCE (mcde_upc.value ,'null'::json ) )::text AS upc , (COALESCE (mcde_tcn.value ,'null'::json ) )::text AS tcn , (COALESCE (mcde_edition.value ,'null'::json ) )::text AS edition , (COALESCE (mcde_physical_description.value ,'null'::json ) )::text AS physical_description , (COALESCE (mcde_publisher.value ,'null'::json ) )::text AS publisher , (COALESCE (mcde_series_title.value ,'null'::json ) )::text AS series_title , (COALESCE (mcde_abstract.value ,'null'::json ) )::text AS abstract , (COALESCE (mcde_toc.value ,'null'::json ) )::text AS toc , (COALESCE (mcde_pubdate.value ,'null'::json ) )::text AS pubdate , (COALESCE (mcde_type_of_resource.value ,'null'::json ) )::text AS type_of_resource FROM ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (biblio.record_entry bre LEFT JOIN metabib.compressed_display_entry mcde_title ON ( ( (bre.id = mcde_title.source) AND (mcde_title.name = 'title'::text) ) ) ) LEFT JOIN metabib.compressed_display_entry mcde_author ON ( ( (bre.id = mcde_author.source) AND (mcde_author.name = 'author'::text) ) ) ) LEFT JOIN metabib.compressed_display_entry mcde_subject ON ( ( (bre.id = mcde_subject.source) AND (mcde_subject.name = 'subject'::text) ) ) ) LEFT JOIN metabib.compressed_display_entry mcde_subject_geographic ON ( ( (bre.id = mcde_subject_geographic.source) AND (mcde_subject_geographic.name = 'subject_geographic'::text) ) ) ) LEFT JOIN metabib.compressed_display_entry mcde_subject_name ON ( ( (bre.id = mcde_subject_name.source) AND (mcde_subject_name.name = 'subject_name'::text) ) ) ) LEFT JOIN metabib.compressed_display_entry mcde_subject_temporal ON ( ( (bre.id = mcde_subject_temporal.source) AND (mcde_subject_temporal.name = 'subject_temporal'::text) ) ) ) LEFT JOIN metabib.compressed_display_entry mcde_subject_topic ON ( ( (bre.id = mcde_subject_topic.source) AND (mcde_subject_topic.name = 'subject_topic'::text) ) ) ) LEFT JOIN metabib.compressed_display_entry mcde_creators ON ( ( (bre.id = mcde_creators.source) AND (mcde_creators.name = 'creators'::text) ) ) ) LEFT JOIN metabib.compressed_display_entry mcde_isbn ON ( ( (bre.id = mcde_isbn.source) AND (mcde_isbn.name = 'isbn'::text) ) ) ) LEFT JOIN metabib.compressed_display_entry mcde_issn ON ( ( (bre.id = mcde_issn.source) AND (mcde_issn.name = 'issn'::text) ) ) ) LEFT JOIN metabib.compressed_display_entry mcde_upc ON ( ( (bre.id = mcde_upc.source) AND (mcde_upc.name = 'upc'::text) ) ) ) LEFT JOIN metabib.compressed_display_entry mcde_tcn ON ( ( (bre.id = mcde_tcn.source) AND (mcde_tcn.name = 'tcn'::text) ) ) ) LEFT JOIN metabib.compressed_display_entry mcde_edition ON ( ( (bre.id = mcde_edition.source) AND (mcde_edition.name = 'edition'::text) ) ) ) LEFT JOIN metabib.compressed_display_entry mcde_physical_description ON ( ( (bre.id = mcde_physical_description.source) AND (mcde_physical_description.name = 'physical_description'::text) ) ) ) LEFT JOIN metabib.compressed_display_entry mcde_publisher ON ( ( (bre.id = mcde_publisher.source) AND (mcde_publisher.name = 'publisher'::text) ) ) ) LEFT JOIN metabib.compressed_display_entry mcde_series_title ON ( ( (bre.id = mcde_series_title.source) AND (mcde_series_title.name = 'series_title'::text) ) ) ) LEFT JOIN metabib.compressed_display_entry mcde_abstract ON ( ( (bre.id = mcde_abstract.source) AND (mcde_abstract.name = 'abstract'::text) ) ) ) LEFT JOIN metabib.compressed_display_entry mcde_toc ON ( ( (bre.id = mcde_toc.source) AND (mcde_toc.name = 'toc'::text) ) ) ) LEFT JOIN metabib.compressed_display_entry mcde_pubdate ON ( ( (bre.id = mcde_pubdate.source) AND (mcde_pubdate.name = 'pubdate'::text) ) ) ) LEFT JOIN metabib.compressed_display_entry mcde_type_of_resource ON ( ( (bre.id = mcde_type_of_resource.source) AND (mcde_type_of_resource.name = 'type_of_resource'::text) ) ) );
Function: metabib.autosuggest_prepare_tsquery(orig text)
Returns: text[]
Language: PLPGSQL
DECLARE orig_ended_in_space BOOLEAN; result RECORD; plain TEXT; normalized TEXT; BEGIN orig_ended_in_space := orig ~ E'\\s$'; orig := ARRAY_TO_STRING( evergreen.regexp_split_to_array(orig, E'\\W+'), ' ' ); normalized := public.naco_normalize(orig); -- also trim()s plain := trim(orig); IF NOT orig_ended_in_space THEN plain := plain || ':*'; normalized := normalized || ':*'; END IF; plain := ARRAY_TO_STRING( evergreen.regexp_split_to_array(plain, E'\\s+'), ' & ' ); normalized := ARRAY_TO_STRING( evergreen.regexp_split_to_array(normalized, E'\\s+'), ' & ' ); RETURN ARRAY[normalized, plain]; END;
Function: metabib.browse(result_limit integer[], pivot_id text, staff integer, context_loc_group integer, context_org boolean, browse_term bigint, search_field integer)
Returns: SET OF flat_browse_entry_appearance
Language: PLPGSQL
DECLARE core_query TEXT; back_query TEXT; forward_query TEXT; pivot_sort_value TEXT; pivot_sort_fallback TEXT; context_locations INT[]; browse_superpage_size INT; results_skipped INT := 0; back_limit INT; back_to_pivot INT; forward_limit INT; forward_to_pivot INT; BEGIN -- First, find the pivot if we were given a browse term but not a pivot. IF pivot_id IS NULL THEN pivot_id := metabib.browse_pivot(search_field, browse_term); END IF; SELECT INTO pivot_sort_value, pivot_sort_fallback sort_value, value FROM metabib.browse_entry WHERE id = pivot_id; -- Bail if we couldn't find a pivot. IF pivot_sort_value IS NULL THEN RETURN; END IF; -- Transform the context_loc_group argument (if any) (logc at the -- TPAC layer) into a form we'll be able to use. IF context_loc_group IS NOT NULL THEN SELECT INTO context_locations ARRAY_AGG(location) FROM asset.copy_location_group_map WHERE lgroup = context_loc_group; END IF; -- Get the configured size of browse superpages. SELECT INTO browse_superpage_size COALESCE(value::INT,100) -- NULL ok FROM config.global_flag WHERE enabled AND name = 'opac.browse.holdings_visibility_test_limit'; -- First we're going to search backward from the pivot, then we're going -- to search forward. In each direction, we need two limits. At the -- lesser of the two limits, we delineate the edge of the result set -- we're going to return. At the greater of the two limits, we find the -- pivot value that would represent an offset from the current pivot -- at a distance of one "page" in either direction, where a "page" is a -- result set of the size specified in the "result_limit" argument. -- -- The two limits in each direction make four derived values in total, -- and we calculate them now. back_limit := CEIL(result_limit::FLOAT / 2); back_to_pivot := result_limit; forward_limit := result_limit / 2; forward_to_pivot := result_limit - 1; -- This is the meat of the SQL query that finds browse entries. We'll -- pass this to a function which uses it with a cursor, so that individual -- rows may be fetched in a loop until some condition is satisfied, without -- waiting for a result set of fixed size to be collected all at once. core_query := ' SELECT mbe.id, mbe.value, mbe.sort_value FROM metabib.browse_entry mbe WHERE ( EXISTS ( -- are there any bibs using this mbe via the requested fields? SELECT 1 FROM metabib.browse_entry_def_map mbedm WHERE mbedm.entry = mbe.id AND mbedm.def = ANY(' || quote_literal(search_field) || ') ) OR EXISTS ( -- are there any authorities using this mbe via the requested fields? SELECT 1 FROM metabib.browse_entry_simple_heading_map mbeshm JOIN authority.simple_heading ash ON ( mbeshm.simple_heading = ash.id ) JOIN authority.control_set_auth_field_metabib_field_map_refs map ON ( ash.atag = map.authority_field AND map.metabib_field = ANY(' || quote_literal(search_field) || ') ) JOIN authority.control_set_authority_field acsaf ON ( map.authority_field = acsaf.id ) JOIN authority.heading_field ahf ON (ahf.id = acsaf.heading_field) WHERE mbeshm.entry = mbe.id AND ahf.heading_purpose IN (' || $$'variant'$$ || ') -- and authority that variant is coming from is linked to a bib AND EXISTS ( SELECT 1 FROM metabib.browse_entry_def_map mbedm2 WHERE mbedm2.authority = ash.record AND mbedm2.def = ANY(' || quote_literal(search_field) || ') ) ) ) AND '; -- This is the variant of the query for browsing backward. back_query := core_query || ' mbe.sort_value <= ' || quote_literal(pivot_sort_value) || ' ORDER BY mbe.sort_value DESC, mbe.value DESC LIMIT 1000'; -- This variant browses forward. forward_query := core_query || ' mbe.sort_value > ' || quote_literal(pivot_sort_value) || ' ORDER BY mbe.sort_value, mbe.value LIMIT 1000'; -- We now call the function which applies a cursor to the provided -- queries, stopping at the appropriate limits and also giving us -- the next page's pivot. RETURN QUERY SELECT * FROM metabib.staged_browse( back_query, search_field, context_org, context_locations, staff, browse_superpage_size, TRUE, back_limit, back_to_pivot ) UNION SELECT * FROM metabib.staged_browse( forward_query, search_field, context_org, context_locations, staff, browse_superpage_size, FALSE, forward_limit, forward_to_pivot ) ORDER BY row_number DESC; END;
Function: metabib.browse(result_limit text, pivot_id text, staff integer, context_loc_group integer, context_org boolean, browse_term bigint, search_class integer)
Returns: SET OF flat_browse_entry_appearance
Language: PLPGSQL
BEGIN RETURN QUERY SELECT * FROM metabib.browse( (SELECT COALESCE(ARRAY_AGG(id), ARRAY[]::INT[]) FROM config.metabib_field WHERE field_class = search_class), browse_term, context_org, context_loc_group, staff, pivot_id, result_limit ); END;
Function: metabib.browse_authority_pivot(integer[], text)
Returns: bigint
Language: SQL
SELECT mbe.id FROM metabib.browse_entry mbe JOIN metabib.browse_entry_simple_heading_map mbeshm ON ( mbeshm.entry = mbe.id ) JOIN authority.simple_heading ash ON ( mbeshm.simple_heading = ash.id ) JOIN authority.control_set_auth_field_metabib_field_map_refs map ON ( ash.atag = map.authority_field AND map.metabib_field = ANY($1) ) WHERE mbe.sort_value >= public.naco_normalize($2) ORDER BY mbe.sort_value, mbe.value LIMIT 1;
Function: metabib.browse_authority_refs_pivot(integer[], text)
Returns: bigint
Language: SQL
SELECT mbe.id FROM metabib.browse_entry mbe JOIN metabib.browse_entry_simple_heading_map mbeshm ON ( mbeshm.entry = mbe.id ) JOIN authority.simple_heading ash ON ( mbeshm.simple_heading = ash.id ) JOIN authority.control_set_auth_field_metabib_field_map_refs_only map ON ( ash.atag = map.authority_field AND map.metabib_field = ANY($1) ) WHERE mbe.sort_value >= public.naco_normalize($2) ORDER BY mbe.sort_value, mbe.value LIMIT 1;
Function: metabib.browse_bib_pivot(integer[], text)
Returns: bigint
Language: SQL
SELECT mbe.id FROM metabib.browse_entry mbe JOIN metabib.browse_entry_def_map mbedm ON ( mbedm.entry = mbe.id AND mbedm.def = ANY($1) ) WHERE mbe.sort_value >= public.naco_normalize($2) ORDER BY mbe.sort_value, mbe.value LIMIT 1;
Function: metabib.browse_normalize(mapped_field text, facet_text integer)
Returns: text
Language: PLPGSQL
DECLARE normalizer RECORD; BEGIN FOR normalizer IN SELECT n.func AS func, n.param_count AS param_count, m.params AS params FROM config.index_normalizer n JOIN config.metabib_field_index_norm_map m ON (m.norm = n.id) WHERE m.field = mapped_field AND m.pos < 0 ORDER BY m.pos LOOP EXECUTE 'SELECT ' || normalizer.func || '(' || quote_literal( facet_text ) || CASE WHEN normalizer.param_count > 0 THEN ',' || REPLACE(REPLACE(BTRIM(normalizer.params,'[]'),E'\'',E'\\\''),E'"',E'\'') ELSE '' END || ')' INTO facet_text; END LOOP; RETURN facet_text; END;
Function: metabib.browse_pivot(integer[], text)
Returns: bigint
Language: SQL
SELECT id FROM metabib.browse_entry WHERE id IN ( metabib.browse_bib_pivot($1, $2), metabib.browse_authority_refs_pivot($1,$2) -- only look in 4xx, 5xx, 7xx of authority ) ORDER BY sort_value, value LIMIT 1;
Function: metabib.compile_composite_attr(cattr_def text)
Returns: query_int
Language: PLPERLU
use JSON::XS; my $json = shift; my $def = decode_json($json); die("Composite attribute definition not supplied") unless $def; my $_cache = (exists $_SHARED{metabib_compile_composite_attr_cache}) ? 1 : 0; return $_SHARED{metabib_compile_composite_attr_cache}{$json} if ($_cache && $_SHARED{metabib_compile_composite_attr_cache}{$json}); sub recurse { my $d = shift; my $j = '&'; my @list; if (ref $d eq 'HASH') { # node or AND if (exists $d->{_attr}) { # it is a node my $plan = spi_prepare('SELECT * FROM metabib.full_attr_id_map WHERE attr = $1 AND value = $2', qw/TEXT TEXT/); my $id = spi_exec_prepared( $plan, {limit => 1}, $d->{_attr}, $d->{_val} )->{rows}[0]{id}; spi_freeplan($plan); return $id; } elsif (exists $d->{_not} && scalar(keys(%$d)) == 1) { # it is a NOT return '!' . recurse($$d{_not}); } else { # an AND list @list = map { recurse($$d{$_}) } sort keys %$d; } } elsif (ref $d eq 'ARRAY') { $j = '|'; @list = map { recurse($_) } @$d; } @list = grep { defined && $_ ne '' } @list; return '(' . join($j,@list) . ')' if @list; return ''; } my $val = recurse($def) || undef; $_SHARED{metabib_compile_composite_attr_cache}{$json} = $val if $_cache; return $val;
Function: metabib.compile_composite_attr(cattr_id integer)
Returns: query_int
Language: SQL
SELECT metabib.compile_composite_attr(definition) FROM config.composite_attr_entry_definition WHERE coded_value = $1;
Function: metabib.compile_composite_attr_cache_disable()
Returns: boolean
Language: PLPERLU
delete $_SHARED{metabib_compile_composite_attr_cache}; return ! exists $_SHARED{metabib_compile_composite_attr_cache};
Function: metabib.compile_composite_attr_cache_init()
Returns: boolean
Language: PLPERLU
$_SHARED{metabib_compile_composite_attr_cache} = {} if ! exists $_SHARED{metabib_compile_composite_attr_cache}; return exists $_SHARED{metabib_compile_composite_attr_cache};
Function: metabib.compile_composite_attr_cache_invalidate()
Returns: boolean
Language: SQL
SELECT metabib.compile_composite_attr_cache_disable() AND metabib.compile_composite_attr_cache_init();
Function: metabib.composite_attr_def_cache_inval_tgr()
Returns: trigger
Language: PLPGSQL
BEGIN PERFORM metabib.compile_composite_attr_cache_invalidate(); RETURN NULL; END;
Function: metabib.display_field_normalize_trigger()
Returns: trigger
Language: PLPGSQL
DECLARE normalizer RECORD; display_field_text TEXT; BEGIN display_field_text := NEW.value; FOR normalizer IN SELECT n.func AS func, n.param_count AS param_count, m.params AS params FROM config.index_normalizer n JOIN config.metabib_field_index_norm_map m ON (m.norm = n.id) WHERE m.field = NEW.field AND m.pos < 0 ORDER BY m.pos LOOP EXECUTE 'SELECT ' || normalizer.func || '(' || quote_literal( display_field_text ) || CASE WHEN normalizer.param_count > 0 THEN ',' || REPLACE(REPLACE(BTRIM( normalizer.params,'[]'),E'\'',E'\\\''),E'"',E'\'') ELSE '' END || ')' INTO display_field_text; END LOOP; NEW.value = display_field_text; RETURN NEW; END;
Function: metabib.facet_normalize_trigger()
Returns: trigger
Language: PLPGSQL
DECLARE normalizer RECORD; facet_text TEXT; BEGIN facet_text := NEW.value; FOR normalizer IN SELECT n.func AS func, n.param_count AS param_count, m.params AS params FROM config.index_normalizer n JOIN config.metabib_field_index_norm_map m ON (m.norm = n.id) WHERE m.field = NEW.field AND m.pos < 0 ORDER BY m.pos LOOP EXECUTE 'SELECT ' || normalizer.func || '(' || quote_literal( facet_text ) || CASE WHEN normalizer.param_count > 0 THEN ',' || REPLACE(REPLACE(BTRIM(normalizer.params,'[]'),E'\'',E'\\\''),E'"',E'\'') ELSE '' END || ')' INTO facet_text; END LOOP; NEW.value = facet_text; RETURN NEW; END;
Function: metabib.reingest_metabib_field_entries(only_fields bigint, skip_search boolean, skip_browse boolean, skip_display boolean, skip_facet boolean, bib_id integer[])
Returns: void
Language: PLPGSQL
DECLARE fclass RECORD; ind_data metabib.field_entry_template%ROWTYPE; mbe_row metabib.browse_entry%ROWTYPE; mbe_id BIGINT; b_skip_facet BOOL; b_skip_display BOOL; b_skip_browse BOOL; b_skip_search BOOL; value_prepped TEXT; field_list INT[] := only_fields; field_types TEXT[] := '{}'::TEXT[]; BEGIN IF field_list = '{}'::INT[] THEN SELECT ARRAY_AGG(id) INTO field_list FROM config.metabib_field; END IF; SELECT COALESCE(NULLIF(skip_facet, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name = 'ingest.skip_facet_indexing' AND enabled)) INTO b_skip_facet; SELECT COALESCE(NULLIF(skip_display, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name = 'ingest.skip_display_indexing' AND enabled)) INTO b_skip_display; SELECT COALESCE(NULLIF(skip_browse, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name = 'ingest.skip_browse_indexing' AND enabled)) INTO b_skip_browse; SELECT COALESCE(NULLIF(skip_search, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name = 'ingest.skip_search_indexing' AND enabled)) INTO b_skip_search; IF NOT b_skip_facet THEN field_types := field_types || '{facet}'; END IF; IF NOT b_skip_display THEN field_types := field_types || '{display}'; END IF; IF NOT b_skip_browse THEN field_types := field_types || '{browse}'; END IF; IF NOT b_skip_search THEN field_types := field_types || '{search}'; END IF; PERFORM * FROM config.internal_flag WHERE name = 'ingest.assume_inserts_only' AND enabled; IF NOT FOUND THEN IF NOT b_skip_search THEN FOR fclass IN SELECT * FROM config.metabib_class LOOP -- RAISE NOTICE 'Emptying out %', fclass.name; EXECUTE $$DELETE FROM metabib.$$ || fclass.name || $$_field_entry WHERE source = $$ || bib_id; END LOOP; END IF; IF NOT b_skip_facet THEN DELETE FROM metabib.facet_entry WHERE source = bib_id; END IF; IF NOT b_skip_display THEN DELETE FROM metabib.display_entry WHERE source = bib_id; END IF; IF NOT b_skip_browse THEN DELETE FROM metabib.browse_entry_def_map WHERE source = bib_id; END IF; END IF; FOR ind_data IN SELECT * FROM biblio.extract_metabib_field_entry( bib_id, ' ', field_types, field_list ) LOOP -- don't store what has been normalized away CONTINUE WHEN ind_data.value IS NULL; IF ind_data.field < 0 THEN ind_data.field = -1 * ind_data.field; END IF; IF ind_data.facet_field AND NOT b_skip_facet THEN INSERT INTO metabib.facet_entry (field, source, value) VALUES (ind_data.field, ind_data.source, ind_data.value); END IF; IF ind_data.display_field AND NOT b_skip_display THEN INSERT INTO metabib.display_entry (field, source, value) VALUES (ind_data.field, ind_data.source, ind_data.value); END IF; IF ind_data.browse_field AND NOT b_skip_browse THEN -- A caveat about this SELECT: this should take care of replacing -- old mbe rows when data changes, but not if normalization (by -- which I mean specifically the output of -- evergreen.oils_tsearch2()) changes. It may or may not be -- expensive to add a comparison of index_vector to index_vector -- to the WHERE clause below. CONTINUE WHEN ind_data.sort_value IS NULL; value_prepped := metabib.browse_normalize(ind_data.value, ind_data.field); IF ind_data.browse_nocase THEN SELECT INTO mbe_row * FROM metabib.browse_entry WHERE evergreen.lowercase(value) = evergreen.lowercase(value_prepped) AND sort_value = ind_data.sort_value ORDER BY sort_value, value LIMIT 1; -- gotta pick something, I guess ELSE SELECT INTO mbe_row * FROM metabib.browse_entry WHERE value = value_prepped AND sort_value = ind_data.sort_value; END IF; IF FOUND THEN mbe_id := mbe_row.id; ELSE INSERT INTO metabib.browse_entry ( value, sort_value ) VALUES ( value_prepped, ind_data.sort_value ); mbe_id := CURRVAL('metabib.browse_entry_id_seq'::REGCLASS); END IF; INSERT INTO metabib.browse_entry_def_map (entry, def, source, authority) VALUES (mbe_id, ind_data.field, ind_data.source, ind_data.authority); END IF; IF ind_data.search_field AND NOT b_skip_search THEN -- Avoid inserting duplicate rows EXECUTE 'SELECT 1 FROM metabib.' || ind_data.field_class || '_field_entry WHERE field = $1 AND source = $2 AND value = $3' INTO mbe_id USING ind_data.field, ind_data.source, ind_data.value; -- RAISE NOTICE 'Search for an already matching row returned %', mbe_id; IF mbe_id IS NULL THEN EXECUTE $$ INSERT INTO metabib.$$ || ind_data.field_class || $$_field_entry (field, source, value) VALUES ($$ || quote_literal(ind_data.field) || $$, $$ || quote_literal(ind_data.source) || $$, $$ || quote_literal(ind_data.value) || $$);$$; END IF; END IF; END LOOP; IF NOT b_skip_search THEN PERFORM metabib.update_combined_index_vectors(bib_id); PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_symspell_reification' AND enabled; IF NOT FOUND THEN PERFORM search.symspell_dictionary_reify(); END IF; END IF; RETURN; END;
Function: metabib.reingest_metabib_full_rec(bib_id bigint)
Returns: void
Language: PLPGSQL
BEGIN PERFORM * FROM config.internal_flag WHERE name = 'ingest.assume_inserts_only' AND enabled; IF NOT FOUND THEN DELETE FROM metabib.real_full_rec WHERE record = bib_id; END IF; INSERT INTO metabib.real_full_rec (record, tag, ind1, ind2, subfield, value) SELECT record, tag, ind1, ind2, subfield, value FROM biblio.flatten_marc( bib_id ); RETURN; END;
Function: metabib.reingest_record_attributes(rdeleted bigint, prmarc text[], pattr_list text, rid boolean)
Returns: void
Language: PLPGSQL
DECLARE transformed_xml TEXT; rmarc TEXT := prmarc; tmp_val TEXT; prev_xfrm TEXT; normalizer RECORD; xfrm config.xml_transform%ROWTYPE; attr_vector INT[] := '{}'::INT[]; attr_vector_tmp INT[]; attr_list TEXT[] := pattr_list; attr_value TEXT[]; norm_attr_value TEXT[]; tmp_xml TEXT; tmp_array TEXT[]; attr_def config.record_attr_definition%ROWTYPE; ccvm_row config.coded_value_map%ROWTYPE; jump_past BOOL; BEGIN IF attr_list IS NULL OR rdeleted THEN -- need to do the full dance on INSERT or undelete SELECT ARRAY_AGG(name) INTO attr_list FROM config.record_attr_definition WHERE ( tag IS NOT NULL OR fixed_field IS NOT NULL OR xpath IS NOT NULL OR phys_char_sf IS NOT NULL OR composite ) AND ( filter OR sorter ); END IF; IF rmarc IS NULL THEN SELECT marc INTO rmarc FROM biblio.record_entry WHERE id = rid; END IF; FOR attr_def IN SELECT * FROM config.record_attr_definition WHERE NOT composite AND name = ANY( attr_list ) ORDER BY format LOOP jump_past := FALSE; -- This gets set when we are non-multi and have found something attr_value := '{}'::TEXT[]; norm_attr_value := '{}'::TEXT[]; attr_vector_tmp := '{}'::INT[]; SELECT * INTO ccvm_row FROM config.coded_value_map c WHERE c.ctype = attr_def.name LIMIT 1; IF attr_def.tag IS NOT NULL THEN -- tag (and optional subfield list) selection SELECT ARRAY_AGG(value) INTO attr_value FROM (SELECT * FROM metabib.full_rec ORDER BY tag, subfield) AS x WHERE record = rid AND tag LIKE attr_def.tag AND CASE WHEN attr_def.sf_list IS NOT NULL THEN POSITION(subfield IN attr_def.sf_list) > 0 ELSE TRUE END GROUP BY tag ORDER BY tag; IF NOT attr_def.multi THEN attr_value := ARRAY[ARRAY_TO_STRING(attr_value, COALESCE(attr_def.joiner,' '))]; jump_past := TRUE; END IF; END IF; IF NOT jump_past AND attr_def.fixed_field IS NOT NULL THEN -- a named fixed field, see config.marc21_ff_pos_map.fixed_field attr_value := attr_value || vandelay.marc21_extract_fixed_field_list(rmarc, attr_def.fixed_field); IF NOT attr_def.multi THEN attr_value := ARRAY[attr_value[1]]; jump_past := TRUE; END IF; END IF; IF NOT jump_past AND attr_def.xpath IS NOT NULL THEN -- and xpath expression SELECT INTO xfrm * FROM config.xml_transform WHERE name = attr_def.format; -- See if we can skip the XSLT ... it's expensive IF prev_xfrm IS NULL OR prev_xfrm <> xfrm.name THEN -- Can't skip the transform IF xfrm.xslt <> '---' THEN transformed_xml := oils_xslt_process(rmarc,xfrm.xslt); ELSE transformed_xml := rmarc; END IF; prev_xfrm := xfrm.name; END IF; IF xfrm.name IS NULL THEN -- just grab the marcxml (empty) transform SELECT INTO xfrm * FROM config.xml_transform WHERE xslt = '---' LIMIT 1; prev_xfrm := xfrm.name; END IF; FOR tmp_xml IN SELECT UNNEST(oils_xpath(attr_def.xpath, transformed_xml, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]])) LOOP tmp_val := oils_xpath_string( '//*', tmp_xml, COALESCE(attr_def.joiner,' '), ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] ); IF tmp_val IS NOT NULL AND BTRIM(tmp_val) <> '' THEN attr_value := attr_value || tmp_val; EXIT WHEN NOT attr_def.multi; END IF; END LOOP; END IF; IF NOT jump_past AND attr_def.phys_char_sf IS NOT NULL THEN -- a named Physical Characteristic, see config.marc21_physical_characteristic_*_map SELECT ARRAY_AGG(m.value) INTO tmp_array FROM vandelay.marc21_physical_characteristics(rmarc) v LEFT JOIN config.marc21_physical_characteristic_value_map m ON (m.id = v.value) WHERE v.subfield = attr_def.phys_char_sf AND (m.value IS NOT NULL AND BTRIM(m.value) <> '') AND ( ccvm_row.id IS NULL OR ( ccvm_row.id IS NOT NULL AND v.id IS NOT NULL) ); attr_value := attr_value || tmp_array; IF NOT attr_def.multi THEN attr_value := ARRAY[attr_value[1]]; END IF; END IF; -- apply index normalizers to attr_value FOR tmp_val IN SELECT value FROM UNNEST(attr_value) x(value) LOOP FOR normalizer IN SELECT n.func AS func, n.param_count AS param_count, m.params AS params FROM config.index_normalizer n JOIN config.record_attr_index_norm_map m ON (m.norm = n.id) WHERE attr = attr_def.name ORDER BY m.pos LOOP EXECUTE 'SELECT ' || normalizer.func || '(' || COALESCE( quote_literal( tmp_val ), 'NULL' ) || CASE WHEN normalizer.param_count > 0 THEN ',' || REPLACE(REPLACE(BTRIM(normalizer.params,'[]'),E'\'',E'\\\''),E'"',E'\'') ELSE '' END || ')' INTO tmp_val; END LOOP; IF tmp_val IS NOT NULL AND tmp_val <> '' THEN -- note that a string that contains only blanks -- is a valid value for some attributes norm_attr_value := norm_attr_value || tmp_val; END IF; END LOOP; IF attr_def.filter THEN -- Create unknown uncontrolled values and find the IDs of the values IF ccvm_row.id IS NULL THEN FOR tmp_val IN SELECT value FROM UNNEST(norm_attr_value) x(value) LOOP IF tmp_val IS NOT NULL AND BTRIM(tmp_val) <> '' THEN BEGIN -- use subtransaction to isolate unique constraint violations INSERT INTO metabib.uncontrolled_record_attr_value ( attr, value ) VALUES ( attr_def.name, tmp_val ); EXCEPTION WHEN unique_violation THEN END; END IF; END LOOP; SELECT ARRAY_AGG(id) INTO attr_vector_tmp FROM metabib.uncontrolled_record_attr_value WHERE attr = attr_def.name AND value = ANY( norm_attr_value ); ELSE SELECT ARRAY_AGG(id) INTO attr_vector_tmp FROM config.coded_value_map WHERE ctype = attr_def.name AND code = ANY( norm_attr_value ); END IF; -- Add the new value to the vector attr_vector := attr_vector || attr_vector_tmp; END IF; IF attr_def.sorter THEN DELETE FROM metabib.record_sorter WHERE source = rid AND attr = attr_def.name; IF norm_attr_value[1] IS NOT NULL THEN INSERT INTO metabib.record_sorter (source, attr, value) VALUES (rid, attr_def.name, norm_attr_value[1]); END IF; END IF; END LOOP; /* We may need to rewrite the vlist to contain the intersection of new values for requested attrs and old values for ignored attrs. To do this, we take the old attr vlist and subtract any values that are valid for the requested attrs, and then add back the new set of attr values. */ IF ARRAY_LENGTH(pattr_list, 1) > 0 THEN SELECT vlist INTO attr_vector_tmp FROM metabib.record_attr_vector_list WHERE source = rid; SELECT attr_vector_tmp - ARRAY_AGG(id::INT) INTO attr_vector_tmp FROM metabib.full_attr_id_map WHERE attr = ANY (pattr_list); attr_vector := attr_vector || attr_vector_tmp; END IF; -- On to composite attributes, now that the record attrs have been pulled. Processed in name order, so later composite -- attributes can depend on earlier ones. PERFORM metabib.compile_composite_attr_cache_init(); FOR attr_def IN SELECT * FROM config.record_attr_definition WHERE composite AND name = ANY( attr_list ) ORDER BY name LOOP FOR ccvm_row IN SELECT * FROM config.coded_value_map c WHERE c.ctype = attr_def.name ORDER BY value LOOP tmp_val := metabib.compile_composite_attr( ccvm_row.id ); CONTINUE WHEN tmp_val IS NULL OR tmp_val = ''; -- nothing to do IF attr_def.filter THEN IF attr_vector @@ tmp_val::query_int THEN attr_vector = attr_vector + intset(ccvm_row.id); EXIT WHEN NOT attr_def.multi; END IF; END IF; IF attr_def.sorter THEN IF attr_vector @@ tmp_val THEN DELETE FROM metabib.record_sorter WHERE source = rid AND attr = attr_def.name; INSERT INTO metabib.record_sorter (source, attr, value) VALUES (rid, attr_def.name, ccvm_row.code); END IF; END IF; END LOOP; END LOOP; IF ARRAY_LENGTH(attr_vector, 1) > 0 THEN IF rdeleted THEN -- initial insert OR revivication DELETE FROM metabib.record_attr_vector_list WHERE source = rid; INSERT INTO metabib.record_attr_vector_list (source, vlist) VALUES (rid, attr_vector); ELSE UPDATE metabib.record_attr_vector_list SET vlist = attr_vector WHERE source = rid; END IF; END IF; END;
Function: metabib.remap_metarecord_for_bib(retain_deleted bigint, bib_is_deleted text, fp boolean, bib_id boolean)
Returns: bigint
Language: PLPGSQL
DECLARE new_mapping BOOL := TRUE; source_count INT; old_mr BIGINT; tmp_mr metabib.metarecord%ROWTYPE; deleted_mrs BIGINT[]; BEGIN -- We need to make sure we're not a deleted master record of an MR IF bib_is_deleted THEN IF NOT retain_deleted THEN -- Go away for any MR that we're master of, unless retained DELETE FROM metabib.metarecord_source_map WHERE source = bib_id; END IF; FOR old_mr IN SELECT id FROM metabib.metarecord WHERE master_record = bib_id LOOP -- Now, are there any more sources on this MR? SELECT COUNT(*) INTO source_count FROM metabib.metarecord_source_map WHERE metarecord = old_mr; IF source_count = 0 AND NOT retain_deleted THEN -- No other records deleted_mrs := ARRAY_APPEND(deleted_mrs, old_mr); -- Just in case... DELETE FROM metabib.metarecord WHERE id = old_mr; ELSE -- indeed there are. Update it with a null cache and recalcualated master record UPDATE metabib.metarecord SET mods = NULL, master_record = (SELECT id FROM biblio.record_entry WHERE fingerprint = fp AND NOT deleted ORDER BY quality DESC, id ASC LIMIT 1) WHERE id = old_mr; END IF; END LOOP; ELSE -- insert or update FOR tmp_mr IN SELECT m.* FROM metabib.metarecord m JOIN metabib.metarecord_source_map s ON (s.metarecord = m.id) WHERE s.source = bib_id LOOP -- Find the first fingerprint-matching IF old_mr IS NULL AND fp = tmp_mr.fingerprint THEN old_mr := tmp_mr.id; new_mapping := FALSE; ELSE -- Our fingerprint changed ... maybe remove the old MR DELETE FROM metabib.metarecord_source_map WHERE metarecord = tmp_mr.id AND source = bib_id; -- remove the old source mapping SELECT COUNT(*) INTO source_count FROM metabib.metarecord_source_map WHERE metarecord = tmp_mr.id; IF source_count = 0 THEN -- No other records deleted_mrs := ARRAY_APPEND(deleted_mrs, tmp_mr.id); DELETE FROM metabib.metarecord WHERE id = tmp_mr.id; END IF; END IF; END LOOP; -- we found no suitable, preexisting MR based on old source maps IF old_mr IS NULL THEN SELECT id INTO old_mr FROM metabib.metarecord WHERE fingerprint = fp; -- is there one for our current fingerprint? IF old_mr IS NULL THEN -- nope, create one and grab its id INSERT INTO metabib.metarecord ( fingerprint, master_record ) VALUES ( fp, bib_id ); SELECT id INTO old_mr FROM metabib.metarecord WHERE fingerprint = fp; ELSE -- indeed there is. update it with a null cache and recalcualated master record UPDATE metabib.metarecord SET mods = NULL, master_record = (SELECT id FROM biblio.record_entry WHERE fingerprint = fp AND NOT deleted ORDER BY quality DESC, id ASC LIMIT 1) WHERE id = old_mr; END IF; ELSE -- there was one we already attached to, update its mods cache and master_record UPDATE metabib.metarecord SET mods = NULL, master_record = (SELECT id FROM biblio.record_entry WHERE fingerprint = fp AND NOT deleted ORDER BY quality DESC, id ASC LIMIT 1) WHERE id = old_mr; END IF; IF new_mapping THEN INSERT INTO metabib.metarecord_source_map (metarecord, source) VALUES (old_mr, bib_id); -- new source mapping END IF; END IF; IF ARRAY_UPPER(deleted_mrs,1) > 0 THEN UPDATE action.hold_request SET target = old_mr WHERE target IN ( SELECT unnest(deleted_mrs) ) AND hold_type = 'M'; -- if we had to delete any MRs above, make sure their holds are moved END IF; RETURN old_mr; END;
Function: metabib.search_class_to_registered_components(search_class text)
Returns: SET OF record
Language: PLPGSQL
DECLARE search_parts TEXT[]; field_name TEXT; search_part_count INTEGER; rec RECORD; registered_class config.metabib_class%ROWTYPE; registered_alias config.metabib_search_alias%ROWTYPE; registered_field config.metabib_field%ROWTYPE; BEGIN search_parts := REGEXP_SPLIT_TO_ARRAY(search_class, E'\\|'); search_part_count := ARRAY_LENGTH(search_parts, 1); IF search_part_count = 0 THEN RETURN; ELSE SELECT INTO registered_class * FROM config.metabib_class WHERE name = search_parts[1]; IF FOUND THEN IF search_part_count < 2 THEN -- all fields rec := (registered_class.name, NULL::INTEGER); RETURN NEXT rec; RETURN; -- done END IF; FOR field_name IN SELECT * FROM UNNEST(search_parts[2:search_part_count]) LOOP SELECT INTO registered_field * FROM config.metabib_field WHERE name = field_name AND field_class = registered_class.name; IF FOUND THEN rec := (registered_class.name, registered_field.id); RETURN NEXT rec; END IF; END LOOP; ELSE -- maybe we have an alias? SELECT INTO registered_alias * FROM config.metabib_search_alias WHERE alias=search_parts[1]; IF NOT FOUND THEN RETURN; ELSE IF search_part_count < 2 THEN -- return w/e the alias says rec := ( registered_alias.field_class, registered_alias.field ); RETURN NEXT rec; RETURN; -- done ELSE FOR field_name IN SELECT * FROM UNNEST(search_parts[2:search_part_count]) LOOP SELECT INTO registered_field * FROM config.metabib_field WHERE name = field_name AND field_class = registered_alias.field_class; IF FOUND THEN rec := ( registered_alias.field_class, registered_field.id ); RETURN NEXT rec; END IF; END LOOP; END IF; END IF; END IF; END IF; END;
Function: metabib.staged_browse(next_pivot_pos text, result_limit integer[], count_up_from_zero integer, browse_superpage_size integer[], staff boolean, context_locations integer, context_org boolean, fields integer, query integer)
Returns: SET OF flat_browse_entry_appearance
Language: PLPGSQL
DECLARE curs REFCURSOR; rec RECORD; qpfts_query TEXT; aqpfts_query TEXT; afields INT[]; bfields INT[]; result_row metabib.flat_browse_entry_appearance%ROWTYPE; results_skipped INT := 0; row_counter INT := 0; row_number INT; slice_start INT; slice_end INT; full_end INT; all_records BIGINT[]; all_brecords BIGINT[]; all_arecords BIGINT[]; superpage_of_records BIGINT[]; superpage_size INT; c_tests TEXT := ''; b_tests TEXT := ''; c_orgs INT[]; unauthorized_entry RECORD; BEGIN IF count_up_from_zero THEN row_number := 0; ELSE row_number := -1; END IF; IF NOT staff THEN SELECT x.c_attrs, x.b_attrs INTO c_tests, b_tests FROM asset.patron_default_visibility_mask() x; END IF; -- b_tests supplies its own query_int operator, c_tests does not IF c_tests <> '' THEN c_tests := c_tests || '&'; END IF; SELECT ARRAY_AGG(id) INTO c_orgs FROM actor.org_unit_descendants(context_org); c_tests := c_tests || search.calculate_visibility_attribute_test('circ_lib',c_orgs) || '&' || search.calculate_visibility_attribute_test('owning_lib',c_orgs); PERFORM 1 FROM config.internal_flag WHERE enabled AND name = 'opac.located_uri.act_as_copy'; IF FOUND THEN b_tests := b_tests || search.calculate_visibility_attribute_test( 'luri_org', (SELECT ARRAY_AGG(id) FROM actor.org_unit_full_path(context_org) x) ); ELSE b_tests := b_tests || search.calculate_visibility_attribute_test( 'luri_org', (SELECT ARRAY_AGG(id) FROM actor.org_unit_ancestors(context_org) x) ); END IF; IF context_locations THEN IF c_tests <> '' THEN c_tests := c_tests || '&'; END IF; c_tests := c_tests || search.calculate_visibility_attribute_test('location',context_locations); END IF; OPEN curs NO SCROLL FOR EXECUTE query; LOOP FETCH curs INTO rec; IF NOT FOUND THEN IF result_row.pivot_point IS NOT NULL THEN RETURN NEXT result_row; END IF; RETURN; END IF; --Is unauthorized? SELECT INTO unauthorized_entry * FROM metabib.browse_entry_simple_heading_map mbeshm INNER JOIN authority.simple_heading ash ON ( mbeshm.simple_heading = ash.id ) INNER JOIN authority.control_set_authority_field acsaf ON ( acsaf.id = ash.atag ) JOIN authority.heading_field ahf ON (ahf.id = acsaf.heading_field) WHERE mbeshm.entry = rec.id AND ahf.heading_purpose = 'variant'; -- Gather aggregate data based on the MBE row we're looking at now, authority axis IF (unauthorized_entry.record IS NOT NULL) THEN --unauthorized term belongs to an auth linked to a bib? SELECT INTO all_arecords, result_row.sees, afields ARRAY_AGG(DISTINCT abl.bib), STRING_AGG(DISTINCT abl.authority::TEXT, $$,$$), ARRAY_AGG(DISTINCT map.metabib_field) FROM authority.bib_linking abl INNER JOIN authority.control_set_auth_field_metabib_field_map_refs map ON ( map.authority_field = unauthorized_entry.atag AND map.metabib_field = ANY(fields) ) WHERE abl.authority = unauthorized_entry.record; ELSE --do usual procedure SELECT INTO all_arecords, result_row.sees, afields ARRAY_AGG(DISTINCT abl.bib), -- bibs to check for visibility STRING_AGG(DISTINCT aal.source::TEXT, $$,$$), -- authority record ids ARRAY_AGG(DISTINCT map.metabib_field) -- authority-tag-linked CMF rows FROM metabib.browse_entry_simple_heading_map mbeshm JOIN authority.simple_heading ash ON ( mbeshm.simple_heading = ash.id ) JOIN authority.authority_linking aal ON ( ash.record = aal.source ) JOIN authority.bib_linking abl ON ( aal.target = abl.authority ) JOIN authority.control_set_auth_field_metabib_field_map_refs map ON ( ash.atag = map.authority_field AND map.metabib_field = ANY(fields) ) JOIN authority.control_set_authority_field acsaf ON ( map.authority_field = acsaf.id ) JOIN authority.heading_field ahf ON (ahf.id = acsaf.heading_field) WHERE mbeshm.entry = rec.id AND ahf.heading_purpose = 'variant'; END IF; -- Gather aggregate data based on the MBE row we're looking at now, bib axis SELECT INTO all_brecords, result_row.authorities, bfields ARRAY_AGG(DISTINCT source), STRING_AGG(DISTINCT authority::TEXT, $$,$$), ARRAY_AGG(DISTINCT def) FROM metabib.browse_entry_def_map WHERE entry = rec.id AND def = ANY(fields); SELECT INTO result_row.fields STRING_AGG(DISTINCT x::TEXT, $$,$$) FROM UNNEST(afields || bfields) x; result_row.sources := 0; result_row.asources := 0; -- Bib-linked vis checking IF ARRAY_UPPER(all_brecords,1) IS NOT NULL THEN SELECT INTO result_row.sources COUNT(DISTINCT b.id) FROM biblio.record_entry b LEFT JOIN asset.copy_vis_attr_cache acvac ON (acvac.record = b.id) WHERE b.id = ANY(all_brecords[1:browse_superpage_size]) AND ( acvac.vis_attr_vector @@ c_tests::query_int OR b.vis_attr_vector @@ b_tests::query_int ); result_row.accurate := TRUE; END IF; -- Authority-linked vis checking IF ARRAY_UPPER(all_arecords,1) IS NOT NULL THEN SELECT INTO result_row.asources COUNT(DISTINCT b.id) FROM biblio.record_entry b LEFT JOIN asset.copy_vis_attr_cache acvac ON (acvac.record = b.id) WHERE b.id = ANY(all_arecords[1:browse_superpage_size]) AND ( acvac.vis_attr_vector @@ c_tests::query_int OR b.vis_attr_vector @@ b_tests::query_int ); result_row.aaccurate := TRUE; END IF; IF result_row.sources > 0 OR result_row.asources > 0 THEN -- The function that calls this function needs row_number in order -- to correctly order results from two different runs of this -- functions. result_row.row_number := row_number; -- Now, if row_counter is still less than limit, return a row. If -- not, but it is less than next_pivot_pos, continue on without -- returning actual result rows until we find -- that next pivot, and return it. IF row_counter < result_limit THEN result_row.browse_entry := rec.id; result_row.value := rec.value; RETURN NEXT result_row; ELSE result_row.browse_entry := NULL; result_row.authorities := NULL; result_row.fields := NULL; result_row.value := NULL; result_row.sources := NULL; result_row.sees := NULL; result_row.accurate := NULL; result_row.aaccurate := NULL; result_row.pivot_point := rec.id; IF row_counter >= next_pivot_pos THEN RETURN NEXT result_row; RETURN; END IF; END IF; IF count_up_from_zero THEN row_number := row_number + 1; ELSE row_number := row_number - 1; END IF; -- row_counter is different from row_number. -- It simply counts up from zero so that we know when -- we've reached our limit. row_counter := row_counter + 1; END IF; END LOOP; END;
Function: metabib.suggest_browse_entries(match text, buoyant text, rank text, field_weight integer, field_match integer, buoyant_and_class_match integer)
Returns: SET OF record
Language: PLPGSQL
DECLARE prepared_query_texts TEXT[]; query TSQUERY; plain_query TSQUERY; opac_visibility_join TEXT; search_class_join TEXT; r_fields RECORD; b_tests TEXT := ''; BEGIN prepared_query_texts := metabib.autosuggest_prepare_tsquery(raw_query_text); query := TO_TSQUERY('keyword', prepared_query_texts[1]); plain_query := TO_TSQUERY('keyword', prepared_query_texts[2]); visibility_org := NULLIF(visibility_org,-1); IF visibility_org IS NOT NULL THEN PERFORM FROM actor.org_unit WHERE id = visibility_org AND parent_ou IS NULL; IF FOUND THEN opac_visibility_join := ''; ELSE PERFORM 1 FROM config.internal_flag WHERE enabled AND name = 'opac.located_uri.act_as_copy'; IF FOUND THEN b_tests := search.calculate_visibility_attribute_test( 'luri_org', (SELECT ARRAY_AGG(id) FROM actor.org_unit_full_path(visibility_org)) ); ELSE b_tests := search.calculate_visibility_attribute_test( 'luri_org', (SELECT ARRAY_AGG(id) FROM actor.org_unit_ancestors(visibility_org)) ); END IF; opac_visibility_join := ' LEFT JOIN asset.copy_vis_attr_cache acvac ON (acvac.record = x.source) LEFT JOIN biblio.record_entry b ON (b.id = x.source) JOIN vm ON (acvac.vis_attr_vector @@ (vm.c_attrs || $$&$$ || search.calculate_visibility_attribute_test( $$circ_lib$$, (SELECT ARRAY_AGG(id) FROM actor.org_unit_descendants($4)) ) )::query_int ) OR (b.vis_attr_vector @@ $$' || b_tests || '$$::query_int) '; END IF; ELSE opac_visibility_join := ''; END IF; -- The following determines whether we only provide suggestsons matching -- the user's selected search_class, or whether we show other suggestions -- too. The reason for MIN() is that for search_classes like -- 'title|proper|uniform' you would otherwise get multiple rows. The -- implication is that if title as a class doesn't have restrict, -- nor does the proper field, but the uniform field does, you're going -- to get 'false' for your overall evaluation of 'should we restrict?' -- To invert that, change from MIN() to MAX(). SELECT INTO r_fields MIN(cmc.restrict::INT) AS restrict_class, MIN(cmf.restrict::INT) AS restrict_field FROM metabib.search_class_to_registered_components(search_class) AS _registered (field_class TEXT, field INT) JOIN config.metabib_class cmc ON (cmc.name = _registered.field_class) LEFT JOIN config.metabib_field cmf ON (cmf.id = _registered.field); -- evaluate 'should we restrict?' IF r_fields.restrict_field::BOOL OR r_fields.restrict_class::BOOL THEN search_class_join := ' JOIN metabib.search_class_to_registered_components($2) AS _registered (field_class TEXT, field INT) ON ( (_registered.field IS NULL AND _registered.field_class = cmf.field_class) OR (_registered.field = cmf.id) ) '; ELSE search_class_join := ' LEFT JOIN metabib.search_class_to_registered_components($2) AS _registered (field_class TEXT, field INT) ON ( _registered.field_class = cmc.name ) '; END IF; RETURN QUERY EXECUTE ' WITH vm AS ( SELECT * FROM asset.patron_default_visibility_mask() ), mbe AS (SELECT * FROM metabib.browse_entry WHERE index_vector @@ $1 LIMIT 10000) SELECT DISTINCT x.value, x.id, x.push, x.restrict, x.weight, x.ts_rank_cd, x.buoyant, TS_HEADLINE(value, $7, $3) FROM (SELECT DISTINCT mbe.value, cmf.id, cmc.buoyant AND _registered.field_class IS NOT NULL AS push, _registered.field = cmf.id AS restrict, cmf.weight, TS_RANK_CD(mbe.index_vector, $1, $6), cmc.buoyant, mbedm.source FROM metabib.browse_entry_def_map mbedm JOIN mbe ON (mbe.id = mbedm.entry) JOIN config.metabib_field cmf ON (cmf.id = mbedm.def) JOIN config.metabib_class cmc ON (cmf.field_class = cmc.name) ' || search_class_join || ' ORDER BY 3 DESC, 4 DESC NULLS LAST, 5 DESC, 6 DESC, 7 DESC, 1 ASC LIMIT 1000) AS x ' || opac_visibility_join || ' ORDER BY 3 DESC, 4 DESC NULLS LAST, 5 DESC, 6 DESC, 7 DESC, 1 ASC LIMIT $5 ' -- sic, repeat the order by clause in the outer select too USING query, search_class, headline_opts, visibility_org, query_limit, normalization, plain_query ; -- sort order: -- buoyant AND chosen class = match class -- chosen field = match field -- field weight -- rank -- buoyancy -- value itself END;
Function: metabib.trim_trailing_punctuation(text)
Returns: text
Language: PLPGSQL
DECLARE result TEXT; last_char TEXT; BEGIN result := $1; last_char = substring(result from '.$'); IF last_char = ',' THEN result := substring(result from '^(.*),$'); ELSIF last_char = '.' THEN -- must have a single word-character following at least one non-word character IF substring(result from '\W\w\.$') IS NULL THEN result := substring(result from '^(.*)\.$'); END IF; ELSIF last_char IN ('/',':',';','=') THEN -- Dangling subtitle/SoR separator IF substring(result from ' .$') IS NOT NULL THEN -- must have a space before last_char result := substring(result from '^(.*) .$'); END IF; END IF; RETURN result; END;
Function: metabib.update_combined_index_vectors(bib_id bigint)
Returns: void
Language: PLPGSQL
DECLARE rdata TSVECTOR; vclass TEXT; vfield INT; rfields INT[]; BEGIN DELETE FROM metabib.combined_keyword_field_entry WHERE record = bib_id; INSERT INTO metabib.combined_keyword_field_entry(record, metabib_field, index_vector) SELECT bib_id, field, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector) FROM metabib.keyword_field_entry WHERE source = bib_id GROUP BY field; INSERT INTO metabib.combined_keyword_field_entry(record, metabib_field, index_vector) SELECT bib_id, NULL, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector) FROM metabib.keyword_field_entry WHERE source = bib_id; DELETE FROM metabib.combined_title_field_entry WHERE record = bib_id; INSERT INTO metabib.combined_title_field_entry(record, metabib_field, index_vector) SELECT bib_id, field, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector) FROM metabib.title_field_entry WHERE source = bib_id GROUP BY field; INSERT INTO metabib.combined_title_field_entry(record, metabib_field, index_vector) SELECT bib_id, NULL, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector) FROM metabib.title_field_entry WHERE source = bib_id; DELETE FROM metabib.combined_author_field_entry WHERE record = bib_id; INSERT INTO metabib.combined_author_field_entry(record, metabib_field, index_vector) SELECT bib_id, field, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector) FROM metabib.author_field_entry WHERE source = bib_id GROUP BY field; INSERT INTO metabib.combined_author_field_entry(record, metabib_field, index_vector) SELECT bib_id, NULL, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector) FROM metabib.author_field_entry WHERE source = bib_id; DELETE FROM metabib.combined_subject_field_entry WHERE record = bib_id; INSERT INTO metabib.combined_subject_field_entry(record, metabib_field, index_vector) SELECT bib_id, field, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector) FROM metabib.subject_field_entry WHERE source = bib_id GROUP BY field; INSERT INTO metabib.combined_subject_field_entry(record, metabib_field, index_vector) SELECT bib_id, NULL, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector) FROM metabib.subject_field_entry WHERE source = bib_id; DELETE FROM metabib.combined_series_field_entry WHERE record = bib_id; INSERT INTO metabib.combined_series_field_entry(record, metabib_field, index_vector) SELECT bib_id, field, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector) FROM metabib.series_field_entry WHERE source = bib_id GROUP BY field; INSERT INTO metabib.combined_series_field_entry(record, metabib_field, index_vector) SELECT bib_id, NULL, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector) FROM metabib.series_field_entry WHERE source = bib_id; DELETE FROM metabib.combined_identifier_field_entry WHERE record = bib_id; INSERT INTO metabib.combined_identifier_field_entry(record, metabib_field, index_vector) SELECT bib_id, field, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector) FROM metabib.identifier_field_entry WHERE source = bib_id GROUP BY field; INSERT INTO metabib.combined_identifier_field_entry(record, metabib_field, index_vector) SELECT bib_id, NULL, strip(COALESCE(string_agg(index_vector::TEXT,' '),'')::tsvector) FROM metabib.identifier_field_entry WHERE source = bib_id; -- For each virtual def, gather the data from the combined real field -- entries and append it to the virtual combined entry. FOR vfield, rfields IN SELECT virtual, ARRAY_AGG(real) FROM config.metabib_field_virtual_map GROUP BY virtual LOOP SELECT field_class INTO vclass FROM config.metabib_field WHERE id = vfield; SELECT string_agg(index_vector::TEXT,' ')::tsvector INTO rdata FROM metabib.combined_all_field_entry WHERE record = bib_id AND metabib_field = ANY (rfields); BEGIN -- I cannot wait for INSERT ON CONFLICT ... 9.5, though EXECUTE $$ INSERT INTO metabib.combined_$$ || vclass || $$_field_entry (record, metabib_field, index_vector) VALUES ($1, $2, $3) $$ USING bib_id, vfield, rdata; EXCEPTION WHEN unique_violation THEN EXECUTE $$ UPDATE metabib.combined_$$ || vclass || $$_field_entry SET index_vector = index_vector || $3 WHERE record = $1 AND metabib_field = $2 $$ USING bib_id, vfield, rdata; WHEN OTHERS THEN -- ignore and move on END; END LOOP; END;
Schema money
Table: money.account_adjustment
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY DEFAULT nextval('money.payment_id_seq'::regclass) | |
xact | bigint | NOT NULL | |
payment_ts | timestamp with time zone | NOT NULL DEFAULT now() | |
voided | boolean | NOT NULL DEFAULT false | |
amount | numeric(6,2) | NOT NULL | |
note | text | ||
amount_collected | numeric(6,2) | NOT NULL | |
accepting_usr | integer | NOT NULL | |
money.billing.id | billing | bigint |
Table money.account_adjustment Inherits bnm_payment,
money_account_adjustment_accepting_usr_idx accepting_usr money_account_adjustment_bill_idx billing money_account_adjustment_payment_ts_idx payment_ts money_account_adjustment_xact_idx xact money_adjustment_id_idx idTable: money.aged_billing
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY | |
xact | bigint | NOT NULL | |
billing_ts | timestamp with time zone | NOT NULL | |
voided | boolean | NOT NULL | |
voider | integer | ||
void_time | timestamp with time zone | ||
amount | numeric(6,2) | NOT NULL | |
billing_type | text | NOT NULL | |
btype | integer | NOT NULL | |
note | text | ||
create_date | timestamp with time zone | NOT NULL | |
period_start | timestamp with time zone | ||
period_end | timestamp with time zone |
Table: money.aged_payment
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY | |
xact | bigint | NOT NULL | |
payment_ts | timestamp with time zone | NOT NULL | |
voided | boolean | NOT NULL | |
amount | numeric(6,2) | NOT NULL | |
note | text | ||
payment_type | text | NOT NULL | |
accepting_usr | integer | ||
cash_drawer | integer | ||
billing | bigint |
View: money.all_billings
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
xact | bigint | ||
billing_ts | timestamp with time zone | ||
voided | boolean | ||
voider | integer | ||
void_time | timestamp with time zone | ||
amount | numeric(6,2) | ||
billing_type | text | ||
btype | integer | ||
note | text | ||
create_date | timestamp with time zone | ||
period_start | timestamp with time zone | ||
period_end | timestamp with time zone |
SELECT billing.id , billing.xact , billing.billing_ts , billing.voided , billing.voider , billing.void_time , billing.amount , billing.billing_type , billing.btype , billing.note , billing.create_date , billing.period_start , billing.period_end FROM money.billing UNION ALL SELECT aged_billing.id , aged_billing.xact , aged_billing.billing_ts , aged_billing.voided , aged_billing.voider , aged_billing.void_time , aged_billing.amount , aged_billing.billing_type , aged_billing.btype , aged_billing.note , aged_billing.create_date , aged_billing.period_start , aged_billing.period_end FROM money.aged_billing;
View: money.all_payments
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
xact | bigint | ||
payment_ts | timestamp with time zone | ||
voided | boolean | ||
amount | numeric(6,2) | ||
note | text | ||
payment_type | name | ||
accepting_usr | integer | ||
cash_drawer | integer | ||
billing | bigint |
SELECT payment_view_for_aging.id , payment_view_for_aging.xact , payment_view_for_aging.payment_ts , payment_view_for_aging.voided , payment_view_for_aging.amount , payment_view_for_aging.note , payment_view_for_aging.payment_type , payment_view_for_aging.accepting_usr , payment_view_for_aging.cash_drawer , payment_view_for_aging.billing FROM money.payment_view_for_aging UNION ALL SELECT aged_payment.id , aged_payment.xact , aged_payment.payment_ts , aged_payment.voided , aged_payment.amount , aged_payment.note , aged_payment.payment_type , aged_payment.accepting_usr , aged_payment.cash_drawer , aged_payment.billing FROM money.aged_payment;
Table: money.billable_xact
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
actor.usr.id | usr | integer | NOT NULL |
xact_start | timestamp with time zone | NOT NULL DEFAULT now() | |
xact_finish | timestamp with time zone | ||
unrecovered | boolean |
View: money.billable_xact_summary
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
usr | integer | ||
xact_start | timestamp with time zone | ||
xact_finish | timestamp with time zone | ||
total_paid | numeric | ||
last_payment_ts | timestamp with time zone | ||
last_payment_note | text | ||
last_payment_type | name | ||
total_owed | numeric | ||
last_billing_ts | timestamp with time zone | ||
last_billing_note | text | ||
last_billing_type | text | ||
balance_owed | numeric | ||
xact_type | name |
SELECT materialized_billable_xact_summary.id , materialized_billable_xact_summary.usr , materialized_billable_xact_summary.xact_start , materialized_billable_xact_summary.xact_finish , materialized_billable_xact_summary.total_paid , materialized_billable_xact_summary.last_payment_ts , materialized_billable_xact_summary.last_payment_note , materialized_billable_xact_summary.last_payment_type , materialized_billable_xact_summary.total_owed , materialized_billable_xact_summary.last_billing_ts , materialized_billable_xact_summary.last_billing_note , materialized_billable_xact_summary.last_billing_type , materialized_billable_xact_summary.balance_owed , materialized_billable_xact_summary.xact_type FROM money.materialized_billable_xact_summary;
View: money.billable_xact_summary_location_view
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
usr | integer | ||
xact_start | timestamp with time zone | ||
xact_finish | timestamp with time zone | ||
total_paid | numeric | ||
last_payment_ts | timestamp with time zone | ||
last_payment_note | text | ||
last_payment_type | name | ||
total_owed | numeric | ||
last_billing_ts | timestamp with time zone | ||
last_billing_note | text | ||
last_billing_type | text | ||
balance_owed | numeric | ||
xact_type | name | ||
billing_location | integer |
SELECT m.id , m.usr , m.xact_start , m.xact_finish , m.total_paid , m.last_payment_ts , m.last_payment_note , m.last_payment_type , m.total_owed , m.last_billing_ts , m.last_billing_note , m.last_billing_type , m.balance_owed , m.xact_type , COALESCE (c.circ_lib , g.billing_location , r.pickup_lib ) AS billing_location FROM ( ( (money.materialized_billable_xact_summary m LEFT JOIN action.circulation c ON ( (c.id = m.id) ) ) LEFT JOIN money.grocery g ON ( (g.id = m.id) ) ) LEFT JOIN booking.reservation r ON ( (r.id = m.id) ) );
View: money.billable_xact_with_void_summary
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
usr | integer | ||
xact_start | timestamp with time zone | ||
xact_finish | timestamp with time zone | ||
total_paid | numeric | ||
last_payment_ts | timestamp with time zone | ||
last_payment_note | text | ||
last_payment_type | name | ||
total_owed | numeric | ||
last_billing_ts | timestamp with time zone | ||
last_billing_note | text | ||
last_billing_type | text | ||
balance_owed | numeric | ||
xact_type | name |
SELECT xact.id , xact.usr , xact.xact_start , xact.xact_finish , sum (credit.amount) AS total_paid , max (credit.payment_ts) AS last_payment_ts , last (credit.note) AS last_payment_note , last (credit.payment_type) AS last_payment_type , sum (debit.amount) AS total_owed , max (debit.billing_ts) AS last_billing_ts , last (debit.note) AS last_billing_note , last (debit.billing_type) AS last_billing_type , (COALESCE (sum (debit.amount) , (0)::numeric ) - COALESCE (sum (credit.amount) , (0)::numeric ) ) AS balance_owed , p.relname AS xact_type FROM ( ( (money.billable_xact xact JOIN pg_class p ON ( (xact.tableoid = p.oid) ) ) LEFT JOIN money.billing debit ON ( (xact.id = debit.xact) ) ) LEFT JOIN money.payment_view credit ON ( (xact.id = credit.xact) ) ) GROUP BY xact.id , xact.usr , xact.xact_start , xact.xact_finish , p.relname ORDER BY (max (debit.billing_ts) ) , (max (credit.payment_ts) );
Table: money.billing
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
xact | bigint | NOT NULL | |
billing_ts | timestamp with time zone | NOT NULL | |
voided | boolean | NOT NULL DEFAULT false | |
voider | integer | ||
void_time | timestamp with time zone | ||
amount | numeric(6,2) | NOT NULL | |
billing_type | text | NOT NULL | |
config.billing_type.id | btype | integer | NOT NULL |
note | text | ||
create_date | timestamp with time zone | NOT NULL DEFAULT now() | |
period_start | timestamp with time zone | ||
period_end | timestamp with time zone |
Tables referencing this one via Foreign Key Constraints:
m_b_create_date_idx create_date m_b_period_end_idx period_end m_b_period_start_idx period_start m_b_time_idx billing_ts m_b_voider_idx voider m_b_xact_idx xactTable: money.bnm_desk_payment
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY DEFAULT nextval('money.payment_id_seq'::regclass) | |
xact | bigint | NOT NULL | |
payment_ts | timestamp with time zone | NOT NULL DEFAULT now() | |
voided | boolean | NOT NULL DEFAULT false | |
amount | numeric(6,2) | NOT NULL | |
note | text | ||
amount_collected | numeric(6,2) | NOT NULL | |
accepting_usr | integer | NOT NULL | |
actor.workstation.id | cash_drawer | integer |
Table money.bnm_desk_payment Inherits bnm_payment,
Table: money.bnm_payment
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY DEFAULT nextval('money.payment_id_seq'::regclass) | |
xact | bigint | NOT NULL | |
payment_ts | timestamp with time zone | NOT NULL DEFAULT now() | |
voided | boolean | NOT NULL DEFAULT false | |
amount | numeric(6,2) | NOT NULL | |
note | text | ||
amount_collected | numeric(6,2) | NOT NULL | |
accepting_usr | integer | NOT NULL |
Table money.bnm_payment Inherits payment,
View: money.bnm_payment_view
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
xact | bigint | ||
payment_ts | timestamp with time zone | ||
voided | boolean | ||
amount | numeric(6,2) | ||
note | text | ||
amount_collected | numeric(6,2) | ||
accepting_usr | integer | ||
payment_type | name |
SELECT p.id , p.xact , p.payment_ts , p.voided , p.amount , p.note , p.amount_collected , p.accepting_usr , c.relname AS payment_type FROM (money.bnm_payment p JOIN pg_class c ON ( (p.tableoid = c.oid) ) );
Table: money.cash_payment
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY DEFAULT nextval('money.payment_id_seq'::regclass) | |
xact | bigint | NOT NULL | |
payment_ts | timestamp with time zone | NOT NULL DEFAULT now() | |
voided | boolean | NOT NULL DEFAULT false | |
amount | numeric(6,2) | NOT NULL | |
note | text | ||
amount_collected | numeric(6,2) | NOT NULL | |
accepting_usr | integer | NOT NULL | |
cash_drawer | integer |
Table money.cash_payment Inherits bnm_desk_payment,
money_cash_id_idx id money_cash_payment_accepting_usr_idx accepting_usr money_cash_payment_cash_drawer_idx cash_drawer money_cash_payment_ts_idx payment_ts money_cash_payment_xact_idx xactView: money.cashdrawer_payment_view
F-Key | Name | Type | Description |
---|---|---|---|
org_unit | integer | ||
cashdrawer | integer | ||
payment_type | name | ||
payment_ts | timestamp with time zone | ||
amount | numeric(6,2) | ||
voided | boolean | ||
note | text |
SELECT ou.id AS org_unit , ws.id AS cashdrawer , t.payment_type , p.payment_ts , p.amount , p.voided , p.note FROM ( ( (actor.org_unit ou JOIN actor.workstation ws ON ( (ou.id = ws.owning_lib) ) ) LEFT JOIN money.bnm_desk_payment p ON ( (ws.id = p.cash_drawer) ) ) LEFT JOIN money.payment_view t ON ( (p.id = t.id) ) );
Table: money.check_payment
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY DEFAULT nextval('money.payment_id_seq'::regclass) | |
xact | bigint | NOT NULL | |
payment_ts | timestamp with time zone | NOT NULL DEFAULT now() | |
voided | boolean | NOT NULL DEFAULT false | |
amount | numeric(6,2) | NOT NULL | |
note | text | ||
amount_collected | numeric(6,2) | NOT NULL | |
accepting_usr | integer | NOT NULL | |
cash_drawer | integer | ||
check_number | text | NOT NULL |
Table money.check_payment Inherits bnm_desk_payment,
money_check_id_idx id money_check_payment_accepting_usr_idx accepting_usr money_check_payment_cash_drawer_idx cash_drawer money_check_payment_ts_idx payment_ts money_check_payment_xact_idx xactTable: money.collections_tracker
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
actor.usr.id | usr | integer | NOT NULL |
actor.usr.id | collector | integer | NOT NULL |
actor.org_unit.id | location | integer | NOT NULL |
enter_time | timestamp with time zone |
Table: money.credit_card_payment
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY DEFAULT nextval('money.payment_id_seq'::regclass) | |
xact | bigint | NOT NULL | |
payment_ts | timestamp with time zone | NOT NULL DEFAULT now() | |
voided | boolean | NOT NULL DEFAULT false | |
amount | numeric(6,2) | NOT NULL | |
note | text | ||
amount_collected | numeric(6,2) | NOT NULL | |
accepting_usr | integer | NOT NULL | |
cash_drawer | integer | ||
cc_number | text | ||
cc_processor | text | ||
cc_order_number | text | ||
approval_code | text |
Table money.credit_card_payment Inherits bnm_desk_payment,
money_credit_card_id_idx id money_credit_card_payment_accepting_usr_idx accepting_usr money_credit_card_payment_cash_drawer_idx cash_drawer money_credit_card_payment_ts_idx payment_ts money_credit_card_payment_xact_idx xactTable: money.credit_payment
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY DEFAULT nextval('money.payment_id_seq'::regclass) | |
xact | bigint | NOT NULL | |
payment_ts | timestamp with time zone | NOT NULL DEFAULT now() | |
voided | boolean | NOT NULL DEFAULT false | |
amount | numeric(6,2) | NOT NULL | |
note | text | ||
amount_collected | numeric(6,2) | NOT NULL | |
accepting_usr | integer | NOT NULL |
Table money.credit_payment Inherits bnm_payment,
money_credit_id_idx id money_credit_payment_accepting_usr_idx accepting_usr money_credit_payment_payment_ts_idx payment_ts money_credit_payment_xact_idx xactTable: money.debit_card_payment
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY DEFAULT nextval('money.payment_id_seq'::regclass) | |
xact | bigint | NOT NULL | |
payment_ts | timestamp with time zone | NOT NULL DEFAULT now() | |
voided | boolean | NOT NULL DEFAULT false | |
amount | numeric(6,2) | NOT NULL | |
note | text | ||
amount_collected | numeric(6,2) | NOT NULL | |
accepting_usr | integer | NOT NULL | |
cash_drawer | integer |
Table money.debit_card_payment Inherits bnm_desk_payment,
money_debit_card_id_idx id money_debit_card_payment_accepting_usr_idx accepting_usr money_debit_card_payment_cash_drawer_idx cash_drawer money_debit_card_payment_ts_idx payment_ts money_debit_card_payment_xact_idx xactView: money.desk_payment_view
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
xact | bigint | ||
payment_ts | timestamp with time zone | ||
voided | boolean | ||
amount | numeric(6,2) | ||
note | text | ||
amount_collected | numeric(6,2) | ||
accepting_usr | integer | ||
cash_drawer | integer | ||
payment_type | name |
SELECT p.id , p.xact , p.payment_ts , p.voided , p.amount , p.note , p.amount_collected , p.accepting_usr , p.cash_drawer , c.relname AS payment_type FROM (money.bnm_desk_payment p JOIN pg_class c ON ( (p.tableoid = c.oid) ) );
Table: money.forgive_payment
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY DEFAULT nextval('money.payment_id_seq'::regclass) | |
xact | bigint | NOT NULL | |
payment_ts | timestamp with time zone | NOT NULL DEFAULT now() | |
voided | boolean | NOT NULL DEFAULT false | |
amount | numeric(6,2) | NOT NULL | |
note | text | ||
amount_collected | numeric(6,2) | NOT NULL | |
accepting_usr | integer | NOT NULL |
Table money.forgive_payment Inherits bnm_payment,
money_forgive_id_idx id money_forgive_payment_accepting_usr_idx accepting_usr money_forgive_payment_payment_ts_idx payment_ts money_forgive_payment_xact_idx xactTable: money.goods_payment
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY DEFAULT nextval('money.payment_id_seq'::regclass) | |
xact | bigint | NOT NULL | |
payment_ts | timestamp with time zone | NOT NULL DEFAULT now() | |
voided | boolean | NOT NULL DEFAULT false | |
amount | numeric(6,2) | NOT NULL | |
note | text | ||
amount_collected | numeric(6,2) | NOT NULL | |
accepting_usr | integer | NOT NULL |
Table money.goods_payment Inherits bnm_payment,
money_goods_id_idx id money_goods_payment_accepting_usr_idx accepting_usr money_goods_payment_payment_ts_idx payment_ts money_goods_payment_xact_idx xactTable: money.grocery
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY DEFAULT nextval('money.billable_xact_id_seq'::regclass) | |
usr | integer | NOT NULL | |
xact_start | timestamp with time zone | NOT NULL DEFAULT now() | |
xact_finish | timestamp with time zone | ||
unrecovered | boolean | ||
billing_location | integer | NOT NULL | |
note | text |
Table money.grocery Inherits billable_xact,
circ_open_date_idx xact_start) WHERE (xact_finish IS NULL m_g_usr_idx usrTable: money.materialized_billable_xact_summary
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY | |
usr | integer | ||
xact_start | timestamp with time zone | ||
xact_finish | timestamp with time zone | ||
total_paid | numeric | ||
last_payment_ts | timestamp with time zone | ||
last_payment_note | text | ||
last_payment_type | name | ||
total_owed | numeric | ||
last_billing_ts | timestamp with time zone | ||
last_billing_note | text | ||
last_billing_type | text | ||
balance_owed | numeric | ||
xact_type | name |
View: money.non_drawer_payment_view
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
xact | bigint | ||
payment_ts | timestamp with time zone | ||
voided | boolean | ||
amount | numeric(6,2) | ||
note | text | ||
amount_collected | numeric(6,2) | ||
accepting_usr | integer | ||
payment_type | name |
SELECT p.id , p.xact , p.payment_ts , p.voided , p.amount , p.note , p.amount_collected , p.accepting_usr , c.relname AS payment_type FROM (money.bnm_payment p JOIN pg_class c ON ( (p.tableoid = c.oid) ) ) WHERE (c.relname <> ALL (ARRAY['cash_payment'::name ,'check_payment'::name ,'credit_card_payment'::name ,'debit_card_payment'::name] ) );
View: money.open_billable_xact_summary
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
usr | integer | ||
xact_start | timestamp with time zone | ||
xact_finish | timestamp with time zone | ||
total_paid | numeric | ||
last_payment_ts | timestamp with time zone | ||
last_payment_note | text | ||
last_payment_type | name | ||
total_owed | numeric | ||
last_billing_ts | timestamp with time zone | ||
last_billing_note | text | ||
last_billing_type | text | ||
balance_owed | numeric | ||
xact_type | name | ||
billing_location | integer |
SELECT billable_xact_summary_location_view.id , billable_xact_summary_location_view.usr , billable_xact_summary_location_view.xact_start , billable_xact_summary_location_view.xact_finish , billable_xact_summary_location_view.total_paid , billable_xact_summary_location_view.last_payment_ts , billable_xact_summary_location_view.last_payment_note , billable_xact_summary_location_view.last_payment_type , billable_xact_summary_location_view.total_owed , billable_xact_summary_location_view.last_billing_ts , billable_xact_summary_location_view.last_billing_note , billable_xact_summary_location_view.last_billing_type , billable_xact_summary_location_view.balance_owed , billable_xact_summary_location_view.xact_type , billable_xact_summary_location_view.billing_location FROM money.billable_xact_summary_location_view WHERE (billable_xact_summary_location_view.xact_finish IS NULL);
View: money.open_transaction_billing_summary
F-Key | Name | Type | Description |
---|---|---|---|
xact | bigint | ||
last_billing_type | text | ||
last_billing_note | text | ||
last_billing_ts | timestamp with time zone | ||
total_owed | numeric |
SELECT billing.xact , last (billing.billing_type) AS last_billing_type , last (billing.note) AS last_billing_note , max (billing.billing_ts) AS last_billing_ts , sum (COALESCE (billing.amount , (0)::numeric ) ) AS total_owed FROM money.billing WHERE (billing.voided IS FALSE) GROUP BY billing.xact ORDER BY (max (billing.billing_ts) );
View: money.open_transaction_billing_type_summary
F-Key | Name | Type | Description |
---|---|---|---|
xact | bigint | ||
last_billing_type | text | ||
last_billing_note | text | ||
last_billing_ts | timestamp with time zone | ||
total_owed | numeric |
SELECT billing.xact , billing.billing_type AS last_billing_type , last (billing.note) AS last_billing_note , max (billing.billing_ts) AS last_billing_ts , sum (COALESCE (billing.amount , (0)::numeric ) ) AS total_owed FROM money.billing WHERE (billing.voided IS FALSE) GROUP BY billing.xact , billing.billing_type ORDER BY (max (billing.billing_ts) );
View: money.open_transaction_payment_summary
F-Key | Name | Type | Description |
---|---|---|---|
xact | bigint | ||
last_payment_type | name | ||
last_payment_note | text | ||
last_payment_ts | timestamp with time zone | ||
total_paid | numeric |
SELECT payment_view.xact , last (payment_view.payment_type) AS last_payment_type , last (payment_view.note) AS last_payment_note , max (payment_view.payment_ts) AS last_payment_ts , sum (COALESCE (payment_view.amount , (0)::numeric ) ) AS total_paid FROM money.payment_view WHERE (payment_view.voided IS FALSE) GROUP BY payment_view.xact ORDER BY (max (payment_view.payment_ts) );
View: money.open_usr_circulation_summary
F-Key | Name | Type | Description |
---|---|---|---|
usr | integer | ||
total_paid | numeric | ||
total_owed | numeric | ||
balance_owed | numeric |
SELECT materialized_billable_xact_summary.usr , sum (materialized_billable_xact_summary.total_paid) AS total_paid , sum (materialized_billable_xact_summary.total_owed) AS total_owed , sum (materialized_billable_xact_summary.balance_owed) AS balance_owed FROM money.materialized_billable_xact_summary WHERE ( (materialized_billable_xact_summary.xact_type = 'circulation'::name) AND (materialized_billable_xact_summary.xact_finish IS NULL) ) GROUP BY materialized_billable_xact_summary.usr;
View: money.open_usr_summary
F-Key | Name | Type | Description |
---|---|---|---|
usr | integer | ||
total_paid | numeric | ||
total_owed | numeric | ||
balance_owed | numeric |
SELECT materialized_billable_xact_summary.usr , sum (materialized_billable_xact_summary.total_paid) AS total_paid , sum (materialized_billable_xact_summary.total_owed) AS total_owed , sum (materialized_billable_xact_summary.balance_owed) AS balance_owed FROM money.materialized_billable_xact_summary WHERE (materialized_billable_xact_summary.xact_finish IS NULL) GROUP BY materialized_billable_xact_summary.usr;
View: money.open_with_balance_usr_summary
F-Key | Name | Type | Description |
---|---|---|---|
usr | integer | ||
total_paid | numeric | ||
total_owed | numeric | ||
balance_owed | numeric |
SELECT materialized_billable_xact_summary.usr , sum (materialized_billable_xact_summary.total_paid) AS total_paid , sum (materialized_billable_xact_summary.total_owed) AS total_owed , sum (materialized_billable_xact_summary.balance_owed) AS balance_owed FROM money.materialized_billable_xact_summary WHERE ( (materialized_billable_xact_summary.xact_finish IS NULL) AND (materialized_billable_xact_summary.balance_owed <> 0.0) ) GROUP BY materialized_billable_xact_summary.usr;
Table: money.payment
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
xact | bigint | NOT NULL | |
payment_ts | timestamp with time zone | NOT NULL DEFAULT now() | |
voided | boolean | NOT NULL DEFAULT false | |
amount | numeric(6,2) | NOT NULL | |
note | text |
View: money.payment_view
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
xact | bigint | ||
payment_ts | timestamp with time zone | ||
voided | boolean | ||
amount | numeric(6,2) | ||
note | text | ||
payment_type | name |
SELECT p.id , p.xact , p.payment_ts , p.voided , p.amount , p.note , c.relname AS payment_type FROM (money.payment p JOIN pg_class c ON ( (p.tableoid = c.oid) ) );
View: money.payment_view_for_aging
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
xact | bigint | ||
payment_ts | timestamp with time zone | ||
voided | boolean | ||
amount | numeric(6,2) | ||
note | text | ||
payment_type | name | ||
accepting_usr | integer | ||
cash_drawer | integer | ||
billing | bigint |
SELECT p.id , p.xact , p.payment_ts , p.voided , p.amount , p.note , p.payment_type , bnm.accepting_usr , bnmd.cash_drawer , maa.billing FROM ( ( (money.payment_view p LEFT JOIN money.bnm_payment bnm ON ( (bnm.id = p.id) ) ) LEFT JOIN money.bnm_desk_payment bnmd ON ( (bnmd.id = p.id) ) ) LEFT JOIN money.account_adjustment maa ON ( (maa.id = p.id) ) );
View: money.transaction_billing_summary
F-Key | Name | Type | Description |
---|---|---|---|
xact | bigint | ||
last_billing_type | text | ||
last_billing_note | text | ||
last_billing_ts | timestamp with time zone | ||
total_owed | numeric |
SELECT materialized_billable_xact_summary.id AS xact , materialized_billable_xact_summary.last_billing_type , materialized_billable_xact_summary.last_billing_note , materialized_billable_xact_summary.last_billing_ts , materialized_billable_xact_summary.total_owed FROM money.materialized_billable_xact_summary;
View: money.transaction_billing_type_summary
F-Key | Name | Type | Description |
---|---|---|---|
xact | bigint | ||
last_billing_type | text | ||
last_billing_note | text | ||
last_billing_ts | timestamp with time zone | ||
total_owed | numeric |
SELECT billing.xact , billing.billing_type AS last_billing_type , last (billing.note) AS last_billing_note , max (billing.billing_ts) AS last_billing_ts , sum (COALESCE (billing.amount , (0)::numeric ) ) AS total_owed FROM money.billing WHERE (billing.voided IS FALSE) GROUP BY billing.xact , billing.billing_type ORDER BY (max (billing.billing_ts) );
View: money.transaction_billing_with_void_summary
F-Key | Name | Type | Description |
---|---|---|---|
xact | bigint | ||
last_billing_type | text | ||
last_billing_note | text | ||
last_billing_ts | timestamp with time zone | ||
total_owed | numeric |
SELECT billing.xact , last (billing.billing_type) AS last_billing_type , last (billing.note) AS last_billing_note , max (billing.billing_ts) AS last_billing_ts , sum ( CASE WHEN billing.voided THEN (0)::numeric ELSE COALESCE (billing.amount , (0)::numeric ) END ) AS total_owed FROM money.billing GROUP BY billing.xact ORDER BY (max (billing.billing_ts) );
View: money.transaction_payment_summary
F-Key | Name | Type | Description |
---|---|---|---|
xact | bigint | ||
last_payment_type | name | ||
last_payment_note | text | ||
last_payment_ts | timestamp with time zone | ||
total_paid | numeric |
SELECT payment_view.xact , last (payment_view.payment_type) AS last_payment_type , last (payment_view.note) AS last_payment_note , max (payment_view.payment_ts) AS last_payment_ts , sum (COALESCE (payment_view.amount , (0)::numeric ) ) AS total_paid FROM money.payment_view WHERE (payment_view.voided IS FALSE) GROUP BY payment_view.xact ORDER BY (max (payment_view.payment_ts) );
View: money.transaction_payment_with_void_summary
F-Key | Name | Type | Description |
---|---|---|---|
xact | bigint | ||
last_payment_type | name | ||
last_payment_note | text | ||
last_payment_ts | timestamp with time zone | ||
total_paid | numeric |
SELECT payment_view.xact , last (payment_view.payment_type) AS last_payment_type , last (payment_view.note) AS last_payment_note , max (payment_view.payment_ts) AS last_payment_ts , sum ( CASE WHEN payment_view.voided THEN (0)::numeric ELSE COALESCE (payment_view.amount , (0)::numeric ) END ) AS total_paid FROM money.payment_view GROUP BY payment_view.xact ORDER BY (max (payment_view.payment_ts) );
View: money.usr_circulation_summary
F-Key | Name | Type | Description |
---|---|---|---|
usr | integer | ||
total_paid | numeric | ||
total_owed | numeric | ||
balance_owed | numeric |
SELECT billable_xact_summary.usr , sum (billable_xact_summary.total_paid) AS total_paid , sum (billable_xact_summary.total_owed) AS total_owed , sum (billable_xact_summary.balance_owed) AS balance_owed FROM money.billable_xact_summary WHERE (billable_xact_summary.xact_type = 'circulation'::name) GROUP BY billable_xact_summary.usr;
View: money.usr_summary
F-Key | Name | Type | Description |
---|---|---|---|
usr | integer | ||
total_paid | numeric | ||
total_owed | numeric | ||
balance_owed | numeric |
SELECT materialized_billable_xact_summary.usr , sum (materialized_billable_xact_summary.total_paid) AS total_paid , sum (materialized_billable_xact_summary.total_owed) AS total_owed , sum (materialized_billable_xact_summary.balance_owed) AS balance_owed FROM money.materialized_billable_xact_summary GROUP BY materialized_billable_xact_summary.usr;
Table: money.work_payment
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY DEFAULT nextval('money.payment_id_seq'::regclass) | |
xact | bigint | NOT NULL | |
payment_ts | timestamp with time zone | NOT NULL DEFAULT now() | |
voided | boolean | NOT NULL DEFAULT false | |
amount | numeric(6,2) | NOT NULL | |
note | text | ||
amount_collected | numeric(6,2) | NOT NULL | |
accepting_usr | integer | NOT NULL |
Table money.work_payment Inherits bnm_payment,
money_work_id_idx id money_work_payment_accepting_usr_idx accepting_usr money_work_payment_payment_ts_idx payment_ts money_work_payment_xact_idx xactFunction: money.age_billings_and_payments()
Returns: integer
Language: PLPGSQL
-- Age billings and payments linked to transactions which were -- completed at least 'older_than' time ago. DECLARE xact_id BIGINT; counter INTEGER DEFAULT 0; keep_age INTERVAL; BEGIN SELECT value::INTERVAL INTO keep_age FROM config.global_flag WHERE name = 'history.money.retention_age' AND enabled; -- Confirm interval-based aging is enabled. IF keep_age IS NULL THEN RETURN counter; END IF; -- Start with non-circulation transactions FOR xact_id IN SELECT DISTINCT(xact.id) FROM money.billable_xact xact -- confirm there is something to age JOIN money.billing mb ON mb.xact = xact.id -- Avoid aging money linked to non-aged circulations. LEFT JOIN action.circulation circ ON circ.id = xact.id WHERE circ.id IS NULL AND AGE(NOW(), xact.xact_finish) > keep_age LOOP PERFORM money.age_billings_and_payments_for_xact(xact_id); counter := counter + 1; END LOOP; -- Then handle aged circulation money. FOR xact_id IN SELECT DISTINCT(xact.id) FROM action.aged_circulation xact -- confirm there is something to age JOIN money.billing mb ON mb.xact = xact.id WHERE AGE(NOW(), xact.xact_finish) > keep_age LOOP PERFORM money.age_billings_and_payments_for_xact(xact_id); counter := counter + 1; END LOOP; RETURN counter; END;
Function: money.age_billings_and_payments_for_xact(xact_id bigint)
Returns: void
Language: SQL
INSERT INTO money.aged_billing SELECT * FROM money.billing WHERE xact = $1; INSERT INTO money.aged_payment SELECT * FROM money.payment_view_for_aging WHERE xact = xact_id; DELETE FROM money.payment WHERE xact = $1; DELETE FROM money.billing WHERE xact = $1;
Function: money.maintain_billing_ts()
Returns: trigger
Language: PLPGSQL
BEGIN NEW.billing_ts := COALESCE(NEW.period_end, NEW.create_date); RETURN NEW; END;
Function: money.mat_summary_create()
Returns: trigger
Language: PLPGSQL
BEGIN INSERT INTO money.materialized_billable_xact_summary (id, usr, xact_start, xact_finish, total_paid, total_owed, balance_owed, xact_type) VALUES ( NEW.id, NEW.usr, NEW.xact_start, NEW.xact_finish, 0.0, 0.0, 0.0, TG_ARGV[0]); RETURN NEW; END;
Function: money.mat_summary_delete()
Returns: trigger
Language: PLPGSQL
BEGIN DELETE FROM money.materialized_billable_xact_summary WHERE id = OLD.id; RETURN OLD; END;
Function: money.mat_summary_update()
Returns: trigger
Language: PLPGSQL
BEGIN UPDATE money.materialized_billable_xact_summary SET usr = NEW.usr, xact_start = NEW.xact_start, xact_finish = NEW.xact_finish WHERE id = NEW.id; RETURN NEW; END;
Function: money.materialized_summary_billing_add()
Returns: trigger
Language: PLPGSQL
BEGIN IF NOT NEW.voided THEN UPDATE money.materialized_billable_xact_summary SET total_owed = COALESCE(total_owed, 0.0::numeric) + NEW.amount, last_billing_ts = NEW.billing_ts, last_billing_note = NEW.note, last_billing_type = NEW.billing_type, balance_owed = balance_owed + NEW.amount WHERE id = NEW.xact; END IF; RETURN NEW; END;
Function: money.materialized_summary_billing_del()
Returns: trigger
Language: PLPGSQL
DECLARE prev_billing money.billing%ROWTYPE; old_billing money.billing%ROWTYPE; BEGIN SELECT * INTO prev_billing FROM money.billing WHERE xact = OLD.xact AND NOT voided ORDER BY billing_ts DESC LIMIT 1 OFFSET 1; SELECT * INTO old_billing FROM money.billing WHERE xact = OLD.xact AND NOT voided ORDER BY billing_ts DESC LIMIT 1; IF OLD.id = old_billing.id THEN UPDATE money.materialized_billable_xact_summary SET last_billing_ts = prev_billing.billing_ts, last_billing_note = prev_billing.note, last_billing_type = prev_billing.billing_type WHERE id = OLD.xact; END IF; IF NOT OLD.voided THEN UPDATE money.materialized_billable_xact_summary SET total_owed = total_owed - OLD.amount, balance_owed = balance_owed - OLD.amount WHERE id = OLD.xact; END IF; RETURN OLD; END;
Function: money.materialized_summary_billing_update()
Returns: trigger
Language: PLPGSQL
DECLARE old_billing money.billing%ROWTYPE; old_voided money.billing%ROWTYPE; BEGIN SELECT * INTO old_billing FROM money.billing WHERE xact = NEW.xact AND NOT voided ORDER BY billing_ts DESC LIMIT 1; SELECT * INTO old_voided FROM money.billing WHERE xact = NEW.xact ORDER BY billing_ts DESC LIMIT 1; IF NEW.voided AND NOT OLD.voided THEN IF OLD.id = old_voided.id THEN UPDATE money.materialized_billable_xact_summary SET last_billing_ts = old_billing.billing_ts, last_billing_note = old_billing.note, last_billing_type = old_billing.billing_type WHERE id = OLD.xact; END IF; UPDATE money.materialized_billable_xact_summary SET total_owed = total_owed - NEW.amount, balance_owed = balance_owed - NEW.amount WHERE id = NEW.xact; ELSIF NOT NEW.voided AND OLD.voided THEN IF OLD.id = old_billing.id THEN UPDATE money.materialized_billable_xact_summary SET last_billing_ts = old_billing.billing_ts, last_billing_note = old_billing.note, last_billing_type = old_billing.billing_type WHERE id = OLD.xact; END IF; UPDATE money.materialized_billable_xact_summary SET total_owed = total_owed + NEW.amount, balance_owed = balance_owed + NEW.amount WHERE id = NEW.xact; ELSE UPDATE money.materialized_billable_xact_summary SET total_owed = total_owed - (OLD.amount - NEW.amount), balance_owed = balance_owed - (OLD.amount - NEW.amount) WHERE id = NEW.xact; END IF; RETURN NEW; END;
Function: money.materialized_summary_payment_add()
Returns: trigger
Language: PLPGSQL
BEGIN IF NOT NEW.voided THEN UPDATE money.materialized_billable_xact_summary SET total_paid = COALESCE(total_paid, 0.0::numeric) + NEW.amount, last_payment_ts = NEW.payment_ts, last_payment_note = NEW.note, last_payment_type = TG_ARGV[0], balance_owed = balance_owed - NEW.amount WHERE id = NEW.xact; END IF; RETURN NEW; END;
Function: money.materialized_summary_payment_del()
Returns: trigger
Language: PLPGSQL
DECLARE prev_payment money.payment_view%ROWTYPE; old_payment money.payment_view%ROWTYPE; BEGIN SELECT * INTO prev_payment FROM money.payment_view WHERE xact = OLD.xact AND NOT voided ORDER BY payment_ts DESC LIMIT 1 OFFSET 1; SELECT * INTO old_payment FROM money.payment_view WHERE xact = OLD.xact AND NOT voided ORDER BY payment_ts DESC LIMIT 1; IF OLD.id = old_payment.id THEN UPDATE money.materialized_billable_xact_summary SET last_payment_ts = prev_payment.payment_ts, last_payment_note = prev_payment.note, last_payment_type = prev_payment.payment_type WHERE id = OLD.xact; END IF; IF NOT OLD.voided THEN UPDATE money.materialized_billable_xact_summary SET total_paid = total_paid - OLD.amount, balance_owed = balance_owed + OLD.amount WHERE id = OLD.xact; END IF; RETURN OLD; END;
Function: money.materialized_summary_payment_update()
Returns: trigger
Language: PLPGSQL
DECLARE old_payment money.payment_view%ROWTYPE; old_voided money.payment_view%ROWTYPE; BEGIN SELECT * INTO old_payment FROM money.payment_view WHERE xact = NEW.xact AND NOT voided ORDER BY payment_ts DESC LIMIT 1; SELECT * INTO old_voided FROM money.payment_view WHERE xact = NEW.xact ORDER BY payment_ts DESC LIMIT 1; IF NEW.voided AND NOT OLD.voided THEN IF OLD.id = old_voided.id THEN UPDATE money.materialized_billable_xact_summary SET last_payment_ts = old_payment.payment_ts, last_payment_note = old_payment.note, last_payment_type = old_payment.payment_type WHERE id = OLD.xact; END IF; UPDATE money.materialized_billable_xact_summary SET total_paid = total_paid - NEW.amount, balance_owed = balance_owed + NEW.amount WHERE id = NEW.xact; ELSIF NOT NEW.voided AND OLD.voided THEN IF OLD.id = old_payment.id THEN UPDATE money.materialized_billable_xact_summary SET last_payment_ts = old_payment.payment_ts, last_payment_note = old_payment.note, last_payment_type = old_payment.payment_type WHERE id = OLD.xact; END IF; UPDATE money.materialized_billable_xact_summary SET total_paid = total_paid + NEW.amount, balance_owed = balance_owed - NEW.amount WHERE id = NEW.xact; ELSE UPDATE money.materialized_billable_xact_summary SET total_paid = total_paid - (OLD.amount - NEW.amount), balance_owed = balance_owed + (OLD.amount - NEW.amount) WHERE id = NEW.xact; END IF; RETURN NEW; END;
Schema oai
View: oai.authority
F-Key | Name | Type | Description |
---|---|---|---|
rec_id | bigint | ||
datestamp | timestamp without time zone | ||
deleted | boolean |
SELECT are.id AS rec_id , timezone ('UTC'::text , are.edit_date ) AS datestamp , are.deleted FROM authority.record_entry are ORDER BY are.id;
View: oai.biblio
F-Key | Name | Type | Description |
---|---|---|---|
rec_id | bigint | ||
datestamp | timestamp without time zone | ||
deleted | boolean |
SELECT bre.id AS rec_id , timezone ('UTC'::text , bre.edit_date ) AS datestamp , bre.deleted FROM biblio.record_entry bre ORDER BY bre.id;
Function: oai.auth_is_visible_by_axis(ax bigint, auth text)
Returns: boolean
Language: SQL
SELECT EXISTS (SELECT 1 FROM authority.browse_axis_authority_field_map m JOIN authority.simple_heading r on (r.atag = m.field AND r.record = auth AND m.axis = ax))
Function: oai.bib_is_visible_at_org_by_copy(org bigint, bib integer)
Returns: boolean
Language: SQL
WITH corgs AS (SELECT array_agg(id) AS list FROM actor.org_unit_descendants(org)) SELECT EXISTS (SELECT 1 FROM asset.copy_vis_attr_cache, corgs WHERE vis_attr_vector @@ search.calculate_visibility_attribute_test('circ_lib', corgs.list)::query_int AND bib=record)
Function: oai.bib_is_visible_at_org_by_luri(org bigint, bib integer)
Returns: boolean
Language: SQL
WITH lorgs AS(SELECT array_agg(id) AS list FROM actor.org_unit_ancestors(org)) SELECT EXISTS (SELECT 1 FROM biblio.record_entry, lorgs WHERE vis_attr_vector @@ search.calculate_visibility_attribute_test('luri_org', lorgs.list)::query_int AND bib=id)
Function: oai.bib_is_visible_by_source(src bigint, bib text)
Returns: boolean
Language: SQL
SELECT EXISTS (SELECT 1 FROM biblio.record_entry b JOIN config.bib_source s ON (b.source = s.id) WHERE transcendant AND s.source = src AND bib=b.id)
Schema offline
Table: offline.script
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
session | text | NOT NULL | |
requestor | integer | NOT NULL | |
create_time | integer | NOT NULL | |
workstation | text | NOT NULL | |
logfile | text | NOT NULL | |
time_delta | integer | NOT NULL | |
count | integer | NOT NULL |
Table: offline.session
F-Key | Name | Type | Description |
---|---|---|---|
key | text | PRIMARY KEY | |
org | integer | NOT NULL | |
description | text | ||
creator | integer | NOT NULL | |
create_time | integer | NOT NULL | |
in_process | integer | NOT NULL | |
start_time | integer | ||
end_time | integer | ||
num_complete | integer | NOT NULL |
Schema permission
Table: permission.grp_penalty_threshold
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
permission.grp_tree.id | grp | integer | UNIQUE#1 NOT NULL |
actor.org_unit.id | org_unit | integer | UNIQUE#1 NOT NULL |
config.standing_penalty.id | penalty | integer | UNIQUE#1 NOT NULL |
threshold | numeric(8,2) | NOT NULL |
Table: permission.grp_perm_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
permission.grp_tree.id | grp | integer | UNIQUE#1 NOT NULL |
permission.perm_list.id | perm | integer | UNIQUE#1 NOT NULL |
depth | integer | NOT NULL | |
grantable | boolean | NOT NULL DEFAULT false |
Table: permission.grp_tree
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE NOT NULL | |
permission.grp_tree.id | parent | integer | |
usergroup | boolean | NOT NULL DEFAULT true | |
perm_interval | interval | NOT NULL DEFAULT '3 years'::interval | |
description | text | ||
application_perm | text | ||
hold_priority | integer | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
grp_tree_parent_idx parentTable: permission.grp_tree_display_entry
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
position | integer | NOT NULL | |
actor.org_unit.id | org | integer | UNIQUE#1 NOT NULL |
permission.grp_tree.id | grp | integer | UNIQUE#1 NOT NULL |
permission.grp_tree_display_entry.id | parent | integer |
Tables referencing this one via Foreign Key Constraints:
Table: permission.perm_list
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
code | text | UNIQUE NOT NULL | |
description | text |
Tables referencing this one via Foreign Key Constraints:
perm_list_code_idx codeTable: permission.usr_grp_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.usr.id | usr | integer | UNIQUE#1 NOT NULL |
permission.grp_tree.id | grp | integer | UNIQUE#1 NOT NULL |
Table: permission.usr_object_perm_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.usr.id | usr | integer | UNIQUE#1 NOT NULL |
permission.perm_list.id | perm | integer | UNIQUE#1 NOT NULL |
object_type | text | UNIQUE#1 NOT NULL | |
object_id | text | UNIQUE#1 NOT NULL | |
grantable | boolean | NOT NULL DEFAULT false |
Table: permission.usr_perm_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.usr.id | usr | integer | UNIQUE#1 NOT NULL |
permission.perm_list.id | perm | integer | UNIQUE#1 NOT NULL |
depth | integer | NOT NULL | |
grantable | boolean | NOT NULL DEFAULT false |
Table: permission.usr_work_ou_map
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.usr.id | usr | integer | UNIQUE#1 NOT NULL |
actor.org_unit.id | work_ou | integer | UNIQUE#1 NOT NULL |
Function: permission.grp_ancestors(integer)
Returns: SET OF grp_tree
Language: SQL
WITH RECURSIVE grp_ancestors_distance(id, distance) AS ( SELECT $1, 0 UNION SELECT ou.parent, ouad.distance+1 FROM permission.grp_tree ou JOIN grp_ancestors_distance ouad ON (ou.id = ouad.id) WHERE ou.parent IS NOT NULL ) SELECT ou.* FROM permission.grp_tree ou JOIN grp_ancestors_distance ouad USING (id) ORDER BY ouad.distance DESC;
Function: permission.grp_ancestors_distance(distance integer)
Returns: SET OF record
Language: SQL
WITH RECURSIVE grp_ancestors_distance(id, distance) AS ( SELECT $1, 0 UNION SELECT pgt.parent, gad.distance+1 FROM permission.grp_tree pgt JOIN grp_ancestors_distance gad ON (pgt.id = gad.id) WHERE pgt.parent IS NOT NULL ) SELECT * FROM grp_ancestors_distance;
Function: permission.grp_descendants(integer)
Returns: SET OF grp_tree
Language: SQL
WITH RECURSIVE descendant_depth AS ( SELECT gr.id, gr.parent FROM permission.grp_tree gr WHERE gr.id = $1 UNION ALL SELECT gr.id, gr.parent FROM permission.grp_tree gr JOIN descendant_depth dd ON (dd.id = gr.parent) ) SELECT gr.* FROM permission.grp_tree gr JOIN descendant_depth USING (id);
Function: permission.grp_descendants_distance(distance integer)
Returns: SET OF record
Language: SQL
WITH RECURSIVE grp_descendants_distance(id, distance) AS ( SELECT $1, 0 UNION SELECT pgt.id, gdd.distance+1 FROM permission.grp_tree pgt JOIN grp_descendants_distance gdd ON (pgt.parent = gdd.id) ) SELECT * FROM grp_descendants_distance;
Function: permission.grp_tree_combined_ancestors(integer, integer)
Returns: SET OF grp_tree
Language: SQL
SELECT * FROM permission.grp_ancestors($1) UNION SELECT * FROM permission.grp_ancestors($2);
Function: permission.grp_tree_common_ancestors(integer, integer)
Returns: SET OF grp_tree
Language: SQL
SELECT * FROM permission.grp_ancestors($1) INTERSECT SELECT * FROM permission.grp_ancestors($2);
Function: permission.grp_tree_full_path(integer)
Returns: SET OF grp_tree
Language: SQL
SELECT * FROM permission.grp_ancestors($1) UNION SELECT * FROM permission.grp_descendants($1);
Function: permission.usr_can_grant_perm(target_ou integer, tperm text, iuser integer)
Returns: boolean
Language: PLPGSQL
DECLARE r_usr actor.usr%ROWTYPE; r_perm permission.usr_perm_map%ROWTYPE; BEGIN SELECT * INTO r_usr FROM actor.usr WHERE id = iuser; IF r_usr.active = FALSE THEN RETURN FALSE; END IF; IF r_usr.super_user = TRUE THEN RETURN TRUE; END IF; FOR r_perm IN SELECT * FROM permission.usr_perms(iuser) p JOIN permission.perm_list l ON (l.id = p.perm) WHERE (l.code = tperm AND p.grantable IS TRUE) LOOP PERFORM * FROM actor.org_unit_descendants(target_ou,r_perm.depth) WHERE id = r_usr.home_ou; IF FOUND THEN RETURN TRUE; ELSE RETURN FALSE; END IF; END LOOP; RETURN FALSE; END;
Function: permission.usr_has_home_perm(target_ou integer, tperm text, iuser integer)
Returns: boolean
Language: PLPGSQL
DECLARE r_usr actor.usr%ROWTYPE; r_perm permission.usr_perm_map%ROWTYPE; BEGIN SELECT * INTO r_usr FROM actor.usr WHERE id = iuser; IF r_usr.active = FALSE THEN RETURN FALSE; END IF; IF r_usr.super_user = TRUE THEN RETURN TRUE; END IF; FOR r_perm IN SELECT * FROM permission.usr_perms(iuser) p JOIN permission.perm_list l ON (l.id = p.perm) WHERE l.code = tperm OR p.perm = -1 LOOP PERFORM * FROM actor.org_unit_descendants(target_ou,r_perm.depth) WHERE id = r_usr.home_ou; IF FOUND THEN RETURN TRUE; ELSE RETURN FALSE; END IF; END LOOP; RETURN FALSE; END;
Function: permission.usr_has_object_perm(integer, text, text, text)
Returns: boolean
Language: SQL
SELECT permission.usr_has_object_perm( $1, $2, $3, $4, -1 );
Function: permission.usr_has_object_perm(target_ou integer, obj_id text, obj_type text, tperm text, iuser integer)
Returns: boolean
Language: PLPGSQL
DECLARE r_usr actor.usr%ROWTYPE; res BOOL; BEGIN SELECT * INTO r_usr FROM actor.usr WHERE id = iuser; IF r_usr.active = FALSE THEN RETURN FALSE; END IF; IF r_usr.super_user = TRUE THEN RETURN TRUE; END IF; SELECT TRUE INTO res FROM permission.usr_object_perm_map WHERE usr = r_usr.id AND object_type = obj_type AND object_id = obj_id; IF FOUND THEN RETURN TRUE; END IF; IF target_ou > -1 THEN RETURN permission.usr_has_perm( iuser, tperm, target_ou); END IF; RETURN FALSE; END;
Function: permission.usr_has_perm(integer, text, integer)
Returns: boolean
Language: SQL
SELECT CASE WHEN permission.usr_has_home_perm( $1, $2, $3 ) THEN TRUE WHEN permission.usr_has_work_perm( $1, $2, $3 ) THEN TRUE ELSE FALSE END;
Function: permission.usr_has_perm_at(perm_code integer, user_id text)
Returns: SET OF integer
Language: SQL
SELECT DISTINCT * FROM permission.usr_has_perm_at_nd( $1, $2 );
Function: permission.usr_has_perm_at_all(perm_code integer, user_id text)
Returns: SET OF integer
Language: SQL
SELECT DISTINCT * FROM permission.usr_has_perm_at_all_nd( $1, $2 );
Function: permission.usr_has_perm_at_all_nd(perm_code integer, user_id text)
Returns: SET OF integer
Language: PLPGSQL
-- -- Return a set of all the org units for which a given user has a given -- permission, granted either directly or through inheritance from a parent -- org unit. -- -- The permissions apply to a minimum depth of the org unit hierarchy, and -- to the subordinates of those org units, for the org unit(s) to which the -- user is assigned. -- -- For purposes of this function, the permission.usr_work_ou_map table -- assigns users to org units. I.e. we ignore the home_ou column of actor.usr. -- -- The result set may contain duplicates, which should be eliminated -- by a DISTINCT clause. -- DECLARE n_head_ou INTEGER; n_child_ou INTEGER; BEGIN FOR n_head_ou IN SELECT DISTINCT * FROM permission.usr_has_perm_at_nd( user_id, perm_code ) LOOP -- -- The permission applies only at a depth greater than the work org unit. -- FOR n_child_ou IN SELECT id FROM actor.org_unit_descendants(n_head_ou) LOOP RETURN NEXT n_child_ou; END LOOP; END LOOP; -- RETURN; -- END;
Function: permission.usr_has_perm_at_nd(perm_code integer, user_id text)
Returns: SET OF integer
Language: PLPGSQL
-- -- Return a set of all the org units for which a given user has a given -- permission, granted directly (not through inheritance from a parent -- org unit). -- -- The permissions apply to a minimum depth of the org unit hierarchy, -- for the org unit(s) to which the user is assigned. (They also apply -- to the subordinates of those org units, but we don't report the -- subordinates here.) -- -- For purposes of this function, the permission.usr_work_ou_map table -- defines which users belong to which org units. I.e. we ignore the -- home_ou column of actor.usr. -- -- The result set may contain duplicates, which should be eliminated -- by a DISTINCT clause. -- DECLARE b_super BOOLEAN; n_perm INTEGER; n_min_depth INTEGER; n_work_ou INTEGER; n_curr_ou INTEGER; n_depth INTEGER; n_curr_depth INTEGER; BEGIN -- -- Check for superuser -- SELECT INTO b_super super_user FROM actor.usr WHERE id = user_id; -- IF NOT FOUND THEN return; -- No user? No permissions. ELSIF b_super THEN -- -- Super user has all permissions everywhere -- FOR n_work_ou IN SELECT id FROM actor.org_unit WHERE parent_ou IS NULL LOOP RETURN NEXT n_work_ou; END LOOP; RETURN; END IF; -- -- Translate the permission name -- to a numeric permission id -- SELECT INTO n_perm id FROM permission.perm_list WHERE code = perm_code; -- IF NOT FOUND THEN RETURN; -- No such permission END IF; -- -- Find the highest-level org unit (i.e. the minimum depth) -- to which the permission is applied for this user -- -- This query is modified from the one in permission.usr_perms(). -- SELECT INTO n_min_depth min( depth ) FROM ( SELECT depth FROM permission.usr_perm_map upm WHERE upm.usr = user_id AND (upm.perm = n_perm OR upm.perm = -1) UNION SELECT gpm.depth FROM permission.grp_perm_map gpm WHERE (gpm.perm = n_perm OR gpm.perm = -1) AND gpm.grp IN ( SELECT (permission.grp_ancestors( (SELECT profile FROM actor.usr WHERE id = user_id) )).id ) UNION SELECT p.depth FROM permission.grp_perm_map p WHERE (p.perm = n_perm OR p.perm = -1) AND p.grp IN ( SELECT (permission.grp_ancestors(m.grp)).id FROM permission.usr_grp_map m WHERE m.usr = user_id ) ) AS x; -- IF NOT FOUND THEN RETURN; -- No such permission for this user END IF; -- -- Identify the org units to which the user is assigned. Note that -- we pay no attention to the home_ou column in actor.usr. -- FOR n_work_ou IN SELECT work_ou FROM permission.usr_work_ou_map WHERE usr = user_id LOOP -- For each org unit to which the user is assigned -- -- Determine the level of the org unit by a lookup in actor.org_unit_type. -- We take it on faith that this depth agrees with the actual hierarchy -- defined in actor.org_unit. -- SELECT INTO n_depth type.depth FROM actor.org_unit_type type INNER JOIN actor.org_unit ou ON ( ou.ou_type = type.id ) WHERE ou.id = n_work_ou; -- IF NOT FOUND THEN CONTINUE; -- Maybe raise exception? END IF; -- -- Compare the depth of the work org unit to the -- minimum depth, and branch accordingly -- IF n_depth = n_min_depth THEN -- -- The org unit is at the right depth, so return it. -- RETURN NEXT n_work_ou; ELSIF n_depth > n_min_depth THEN -- -- Traverse the org unit tree toward the root, -- until you reach the minimum depth determined above -- n_curr_depth := n_depth; n_curr_ou := n_work_ou; WHILE n_curr_depth > n_min_depth LOOP SELECT INTO n_curr_ou parent_ou FROM actor.org_unit WHERE id = n_curr_ou; -- IF FOUND THEN n_curr_depth := n_curr_depth - 1; ELSE -- -- This can happen only if the hierarchy defined in -- actor.org_unit is corrupted, or out of sync with -- the depths defined in actor.org_unit_type. -- Maybe we should raise an exception here, instead -- of silently ignoring the problem. -- n_curr_ou = NULL; EXIT; END IF; END LOOP; -- IF n_curr_ou IS NOT NULL THEN RETURN NEXT n_curr_ou; END IF; ELSE -- -- The permission applies only at a depth greater than the work org unit. -- Use connectby() to find all dependent org units at the specified depth. -- FOR n_curr_ou IN SELECT id FROM actor.org_unit_descendants_distance(n_work_ou) WHERE distance = n_min_depth - n_depth LOOP RETURN NEXT n_curr_ou; END LOOP; END IF; -- END LOOP; -- RETURN; -- END;
Function: permission.usr_has_work_perm(target_ou integer, tperm text, iuser integer)
Returns: boolean
Language: PLPGSQL
DECLARE r_woum permission.usr_work_ou_map%ROWTYPE; r_usr actor.usr%ROWTYPE; r_perm permission.usr_perm_map%ROWTYPE; BEGIN SELECT * INTO r_usr FROM actor.usr WHERE id = iuser; IF r_usr.active = FALSE THEN RETURN FALSE; END IF; IF r_usr.super_user = TRUE THEN RETURN TRUE; END IF; FOR r_perm IN SELECT * FROM permission.usr_perms(iuser) p JOIN permission.perm_list l ON (l.id = p.perm) WHERE l.code = tperm OR p.perm = -1 LOOP FOR r_woum IN SELECT * FROM permission.usr_work_ou_map WHERE usr = iuser LOOP PERFORM * FROM actor.org_unit_descendants(target_ou,r_perm.depth) WHERE id = r_woum.work_ou; IF FOUND THEN RETURN TRUE; END IF; END LOOP; END LOOP; RETURN FALSE; END;
Function: permission.usr_perms(integer)
Returns: SET OF usr_perm_map
Language: SQL
SELECT DISTINCT ON (usr,perm) * FROM ( (SELECT * FROM permission.usr_perm_map WHERE usr = $1) UNION ALL (SELECT -p.id, $1 AS usr, p.perm, p.depth, p.grantable FROM permission.grp_perm_map p WHERE p.grp IN ( SELECT (permission.grp_ancestors( (SELECT profile FROM actor.usr WHERE id = $1) )).id ) ) UNION ALL (SELECT -p.id, $1 AS usr, p.perm, p.depth, p.grantable FROM permission.grp_perm_map p WHERE p.grp IN (SELECT (permission.grp_ancestors(m.grp)).id FROM permission.usr_grp_map m WHERE usr = $1)) ) AS x ORDER BY 2, 3, 4 ASC, 5 DESC ;
Schema public
standard public schema
Function: public._int_contained(integer[], integer[])
Returns: boolean
Language: C
contained in
_int_contained
Function: public._int_contained_joinsel(internal, oid, internal, smallint, internal)
Returns: double precision
Language: C
_int_contained_joinsel
Function: public._int_contained_sel(internal, oid, internal, integer)
Returns: double precision
Language: C
_int_contained_sel
Function: public._int_contains(integer[], integer[])
Returns: boolean
Language: C
contains
_int_contains
Function: public._int_contains_joinsel(internal, oid, internal, smallint, internal)
Returns: double precision
Language: C
_int_contains_joinsel
Function: public._int_contains_sel(internal, oid, internal, integer)
Returns: double precision
Language: C
_int_contains_sel
Function: public._int_different(integer[], integer[])
Returns: boolean
Language: C
different
_int_different
Function: public._int_inter(integer[], integer[])
Returns: integer[]
Language: C
_int_inter
Function: public._int_matchsel(internal, oid, internal, integer)
Returns: double precision
Language: C
_int_matchsel
Function: public._int_overlap(integer[], integer[])
Returns: boolean
Language: C
overlaps
_int_overlap
Function: public._int_overlap_joinsel(internal, oid, internal, smallint, internal)
Returns: double precision
Language: C
_int_overlap_joinsel
Function: public._int_overlap_sel(internal, oid, internal, integer)
Returns: double precision
Language: C
_int_overlap_sel
Function: public._int_same(integer[], integer[])
Returns: boolean
Language: C
same as
_int_same
Function: public._int_union(integer[], integer[])
Returns: integer[]
Language: C
_int_union
Function: public._intbig_in(cstring)
Returns: intbig_gkey
Language: C
_intbig_in
Function: public._intbig_out(public.intbig_gkey)
Returns: cstring
Language: C
_intbig_out
Function: public.agg_text(text)
Returns: text
Language: INTERNAL
aggregate_dummy
Function: public.akeys(public.hstore)
Returns: text[]
Language: C
hstore_akeys
Function: public.approximate_date(text, text)
Returns: text
Language: SQL
SELECT REGEXP_REPLACE( $1, E'\\D', $2, 'g' );
Function: public.approximate_high_date(text)
Returns: text
Language: SQL
SELECT approximate_date( $1, '9');
Function: public.approximate_low_date(text)
Returns: text
Language: SQL
SELECT approximate_date( $1, '0');
Function: public.armor(bytea)
Returns: text
Language: C
pg_armor
Function: public.armor(bytea, text[], text[])
Returns: text
Language: C
pg_armor
Function: public.avals(public.hstore)
Returns: text[]
Language: C
hstore_avals
Function: public.boolop(integer[], public.query_int)
Returns: boolean
Language: C
boolean operation with array
boolop
Function: public.bqarr_in(cstring)
Returns: query_int
Language: C
bqarr_in
Function: public.bqarr_out(public.query_int)
Returns: cstring
Language: C
bqarr_out
Function: public.call_number_dewey(text)
Returns: text
Language: PLPERLU
my $txt = shift; $txt =~ s/^\s+//o; $txt =~ s/[\[\]\{\}\(\)`'"#<>\*\?\-\+\$\\]+//og; $txt =~ s/\s+$//o; if ($txt =~ /(\d{3}(?:\.\d+)?)/o) { return $1; } else { return (split /\s+/, $txt)[0]; }
Function: public.call_number_dewey(text, integer)
Returns: text
Language: SQL
SELECT SUBSTRING(call_number_dewey($1) FROM 1 FOR $2);
Function: public.cleanup_acq_marc()
Returns: trigger
Language: PLPGSQL
BEGIN IF TG_OP = 'UPDATE' THEN DELETE FROM acq.lineitem_attr WHERE lineitem = OLD.id AND attr_type IN ('lineitem_provider_attr_definition', 'lineitem_marc_attr_definition','lineitem_generated_attr_definition'); RETURN NEW; ELSE DELETE FROM acq.lineitem_attr WHERE lineitem = OLD.id; RETURN OLD; END IF; END;
Function: public.content_or_null(text)
Returns: text
Language: SQL
SELECT CASE WHEN $1 ~ E'^\\s*$' THEN NULL ELSE $1 END
Function: public.crypt(text, text)
Returns: text
Language: C
pg_crypt
Function: public.cube(double precision)
Returns: cube
Language: C
cube_f8
Function: public.cube(double precision, double precision)
Returns: cube
Language: C
cube_f8_f8
Function: public.cube(double precision[])
Returns: cube
Language: C
cube_a_f8
Function: public.cube(double precision[], double precision[])
Returns: cube
Language: C
cube_a_f8_f8
Function: public.cube(public.cube, double precision)
Returns: cube
Language: C
cube_c_f8
Function: public.cube(public.cube, double precision, double precision)
Returns: cube
Language: C
cube_c_f8_f8
Function: public.cube_cmp(public.cube, public.cube)
Returns: integer
Language: C
btree comparison function
cube_cmp
Function: public.cube_contained(public.cube, public.cube)
Returns: boolean
Language: C
contained in
cube_contained
Function: public.cube_contains(public.cube, public.cube)
Returns: boolean
Language: C
contains
cube_contains
Function: public.cube_coord(public.cube, integer)
Returns: double precision
Language: C
cube_coord
Function: public.cube_coord_llur(public.cube, integer)
Returns: double precision
Language: C
cube_coord_llur
Function: public.cube_dim(public.cube)
Returns: integer
Language: C
cube_dim
Function: public.cube_distance(public.cube, public.cube)
Returns: double precision
Language: C
cube_distance
Function: public.cube_enlarge(public.cube, double precision, integer)
Returns: cube
Language: C
cube_enlarge
Function: public.cube_eq(public.cube, public.cube)
Returns: boolean
Language: C
same as
cube_eq
Function: public.cube_ge(public.cube, public.cube)
Returns: boolean
Language: C
greater than or equal to
cube_ge
Function: public.cube_gt(public.cube, public.cube)
Returns: boolean
Language: C
greater than
cube_gt
Function: public.cube_in(cstring)
Returns: cube
Language: C
cube_in
Function: public.cube_inter(public.cube, public.cube)
Returns: cube
Language: C
cube_inter
Function: public.cube_is_point(public.cube)
Returns: boolean
Language: C
cube_is_point
Function: public.cube_le(public.cube, public.cube)
Returns: boolean
Language: C
lower than or equal to
cube_le
Function: public.cube_ll_coord(public.cube, integer)
Returns: double precision
Language: C
cube_ll_coord
Function: public.cube_lt(public.cube, public.cube)
Returns: boolean
Language: C
lower than
cube_lt
Function: public.cube_ne(public.cube, public.cube)
Returns: boolean
Language: C
different
cube_ne
Function: public.cube_out(public.cube)
Returns: cstring
Language: C
cube_out
Function: public.cube_overlap(public.cube, public.cube)
Returns: boolean
Language: C
overlaps
cube_overlap
Function: public.cube_size(public.cube)
Returns: double precision
Language: C
cube_size
Function: public.cube_subset(public.cube, integer[])
Returns: cube
Language: C
cube_subset
Function: public.cube_union(public.cube, public.cube)
Returns: cube
Language: C
cube_union
Function: public.cube_ur_coord(public.cube, integer)
Returns: double precision
Language: C
cube_ur_coord
Function: public.dearmor(text)
Returns: bytea
Language: C
pg_dearmor
Function: public.decrypt(bytea, bytea, text)
Returns: bytea
Language: C
pg_decrypt
Function: public.decrypt_iv(bytea, bytea, bytea, text)
Returns: bytea
Language: C
pg_decrypt_iv
Function: public.defined(public.hstore, text)
Returns: boolean
Language: C
hstore_defined
Function: public.delete(public.hstore, public.hstore)
Returns: hstore
Language: C
hstore_delete_hstore
Function: public.delete(public.hstore, text)
Returns: hstore
Language: C
hstore_delete
Function: public.delete(public.hstore, text[])
Returns: hstore
Language: C
hstore_delete_array
Function: public.difference(text, text)
Returns: integer
Language: C
difference
Function: public.digest(bytea, text)
Returns: bytea
Language: C
pg_digest
Function: public.digest(text, text)
Returns: bytea
Language: C
pg_digest
Function: public.distance_chebyshev(public.cube, public.cube)
Returns: double precision
Language: C
distance_chebyshev
Function: public.distance_taxicab(public.cube, public.cube)
Returns: double precision
Language: C
distance_taxicab
Function: public.dmetaphone(text)
Returns: text
Language: C
dmetaphone
Function: public.dmetaphone_alt(text)
Returns: text
Language: C
dmetaphone_alt
Function: public.each(value public.hstore)
Returns: SET OF record
Language: C
hstore_each
Function: public.earth()
Returns: double precision
Language: SQL
SELECT '6378168'::float8
Function: public.earth_box(public.earth, double precision)
Returns: cube
Language: SQL
SELECT cube_enlarge($1, gc_to_sec($2), 3)
Function: public.earth_distance(public.earth, public.earth)
Returns: double precision
Language: SQL
SELECT sec_to_gc(cube_distance($1, $2))
Function: public.encrypt(bytea, bytea, text)
Returns: bytea
Language: C
pg_encrypt
Function: public.encrypt_iv(bytea, bytea, bytea, text)
Returns: bytea
Language: C
pg_encrypt_iv
Function: public.entityize(text)
Returns: text
Language: PLPERLU
use Unicode::Normalize; my $x = NFC(shift); $x =~ s/([\x{0080}-\x{fffd}])/sprintf('&#x%X;',ord($1))/sgoe; return $x;
Function: public.exist(public.hstore, text)
Returns: boolean
Language: C
hstore_exists
Function: public.exists_all(public.hstore, text[])
Returns: boolean
Language: C
hstore_exists_all
Function: public.exists_any(public.hstore, text[])
Returns: boolean
Language: C
hstore_exists_any
Function: public.extract_acq_marc_field(bigint, text, text)
Returns: text
Language: SQL
SELECT extract_marc_field('acq.lineitem', $1, $2, $3);
Function: public.extract_acq_marc_field_set(bigint, text, text)
Returns: SET OF text
Language: SQL
SELECT extract_marc_field_set('acq.lineitem', $1, $2, $3);
Function: public.fetchval(public.hstore, text)
Returns: text
Language: C
hstore_fetchval
Function: public.first(anyelement)
Returns: anyelement
Language: INTERNAL
aggregate_dummy
Function: public.first5(text)
Returns: text
Language: SQL
SELECT SUBSTRING( $1, 1, 5);
Function: public.first_agg(anyelement, anyelement)
Returns: anyelement
Language: SQL
SELECT CASE WHEN $1 IS NULL THEN $2 ELSE $1 END;
Function: public.first_word(text)
Returns: text
Language: SQL
SELECT COALESCE(SUBSTRING( $1 FROM $_$^\S+$_$), '');
Function: public.force_to_isbn13(text)
Returns: text
Language: PLPERLU
Inspired by translate_isbn1013 The force_to_isbn13 function takes an input ISBN and returns the ISBN13 version without hypens and with a repaired checksum if the checksum was bad
use Business::ISBN; use strict; use warnings; # Find the first ISBN, force it to ISBN13 and return it my $input = shift; foreach my $word (split(/\s/, $input)) { my $isbn = Business::ISBN->new($word); # First check the checksum; if it is not valid, fix it and add the original # bad-checksum ISBN to the output if ($isbn && $isbn->is_valid_checksum() == Business::ISBN::BAD_CHECKSUM) { $isbn->fix_checksum(); } # If we now have a valid ISBN, force it to ISBN13 and return it return $isbn->as_isbn13->isbn if ($isbn && $isbn->is_valid()); } return undef;
Function: public.g_cube_compress(internal)
Returns: internal
Language: C
g_cube_compress
Function: public.g_cube_consistent(internal, public.cube, smallint, oid, internal)
Returns: boolean
Language: C
g_cube_consistent
Function: public.g_cube_decompress(internal)
Returns: internal
Language: C
g_cube_decompress
Function: public.g_cube_distance(internal, public.cube, smallint, oid, internal)
Returns: double precision
Language: C
g_cube_distance
Function: public.g_cube_penalty(internal, internal, internal)
Returns: internal
Language: C
g_cube_penalty
Function: public.g_cube_picksplit(internal, internal)
Returns: internal
Language: C
g_cube_picksplit
Function: public.g_cube_same(public.cube, public.cube, internal)
Returns: internal
Language: C
g_cube_same
Function: public.g_cube_union(internal, internal)
Returns: cube
Language: C
g_cube_union
Function: public.g_int_compress(internal)
Returns: internal
Language: C
g_int_compress
Function: public.g_int_consistent(internal, integer[], smallint, oid, internal)
Returns: boolean
Language: C
g_int_consistent
Function: public.g_int_decompress(internal)
Returns: internal
Language: C
g_int_decompress
Function: public.g_int_penalty(internal, internal, internal)
Returns: internal
Language: C
g_int_penalty
Function: public.g_int_picksplit(internal, internal)
Returns: internal
Language: C
g_int_picksplit
Function: public.g_int_same(integer[], integer[], internal)
Returns: internal
Language: C
g_int_same
Function: public.g_int_union(internal, internal)
Returns: integer[]
Language: C
g_int_union
Function: public.g_intbig_compress(internal)
Returns: internal
Language: C
g_intbig_compress
Function: public.g_intbig_consistent(internal, integer[], smallint, oid, internal)
Returns: boolean
Language: C
g_intbig_consistent
Function: public.g_intbig_decompress(internal)
Returns: internal
Language: C
g_intbig_decompress
Function: public.g_intbig_penalty(internal, internal, internal)
Returns: internal
Language: C
g_intbig_penalty
Function: public.g_intbig_picksplit(internal, internal)
Returns: internal
Language: C
g_intbig_picksplit
Function: public.g_intbig_same(public.intbig_gkey, public.intbig_gkey, internal)
Returns: internal
Language: C
g_intbig_same
Function: public.g_intbig_union(internal, internal)
Returns: intbig_gkey
Language: C
g_intbig_union
Function: public.gc_to_sec(double precision)
Returns: double precision
Language: SQL
SELECT CASE WHEN $1 < 0 THEN 0::float8 WHEN $1/earth() > pi() THEN 2*earth() ELSE 2*earth()*sin($1/(2*earth())) END
Function: public.gen_random_bytes(integer)
Returns: bytea
Language: C
pg_random_bytes
Function: public.gen_random_uuid()
Returns: uuid
Language: C
pg_random_uuid
Function: public.gen_salt(text)
Returns: text
Language: C
pg_gen_salt
Function: public.gen_salt(text, integer)
Returns: text
Language: C
pg_gen_salt_rounds
Function: public.geo_distance(point, point)
Returns: double precision
Language: C
geo_distance
Function: public.ghstore_compress(internal)
Returns: internal
Language: C
ghstore_compress
Function: public.ghstore_consistent(internal, public.hstore, smallint, oid, internal)
Returns: boolean
Language: C
ghstore_consistent
Function: public.ghstore_decompress(internal)
Returns: internal
Language: C
ghstore_decompress
Function: public.ghstore_in(cstring)
Returns: ghstore
Language: C
ghstore_in
Function: public.ghstore_out(public.ghstore)
Returns: cstring
Language: C
ghstore_out
Function: public.ghstore_penalty(internal, internal, internal)
Returns: internal
Language: C
ghstore_penalty
Function: public.ghstore_picksplit(internal, internal)
Returns: internal
Language: C
ghstore_picksplit
Function: public.ghstore_same(public.ghstore, public.ghstore, internal)
Returns: internal
Language: C
ghstore_same
Function: public.ghstore_union(internal, internal)
Returns: ghstore
Language: C
ghstore_union
Function: public.gin_consistent_hstore(internal, smallint, public.hstore, integer, internal, internal)
Returns: boolean
Language: C
gin_consistent_hstore
Function: public.gin_extract_hstore(public.hstore, internal)
Returns: internal
Language: C
gin_extract_hstore
Function: public.gin_extract_hstore_query(public.hstore, internal, smallint, internal, internal)
Returns: internal
Language: C
gin_extract_hstore_query
Function: public.gin_extract_query_trgm(text, internal, smallint, internal, internal, internal, internal)
Returns: internal
Language: C
gin_extract_query_trgm
Function: public.gin_extract_value_trgm(text, internal)
Returns: internal
Language: C
gin_extract_value_trgm
Function: public.gin_trgm_consistent(internal, smallint, text, integer, internal, internal, internal, internal)
Returns: boolean
Language: C
gin_trgm_consistent
Function: public.gin_trgm_triconsistent(internal, smallint, text, integer, internal, internal, internal)
Returns: "char"
Language: C
gin_trgm_triconsistent
Function: public.ginint4_consistent(internal, smallint, integer[], integer, internal, internal, internal, internal)
Returns: boolean
Language: C
ginint4_consistent
Function: public.ginint4_queryextract(integer[], internal, smallint, internal, internal, internal, internal)
Returns: internal
Language: C
ginint4_queryextract
Function: public.gtrgm_compress(internal)
Returns: internal
Language: C
gtrgm_compress
Function: public.gtrgm_consistent(internal, text, smallint, oid, internal)
Returns: boolean
Language: C
gtrgm_consistent
Function: public.gtrgm_decompress(internal)
Returns: internal
Language: C
gtrgm_decompress
Function: public.gtrgm_distance(internal, text, smallint, oid, internal)
Returns: double precision
Language: C
gtrgm_distance
Function: public.gtrgm_in(cstring)
Returns: gtrgm
Language: C
gtrgm_in
Function: public.gtrgm_out(public.gtrgm)
Returns: cstring
Language: C
gtrgm_out
Function: public.gtrgm_penalty(internal, internal, internal)
Returns: internal
Language: C
gtrgm_penalty
Function: public.gtrgm_picksplit(internal, internal)
Returns: internal
Language: C
gtrgm_picksplit
Function: public.gtrgm_same(public.gtrgm, public.gtrgm, internal)
Returns: internal
Language: C
gtrgm_same
Function: public.gtrgm_union(internal, internal)
Returns: gtrgm
Language: C
gtrgm_union
Function: public.hmac(bytea, bytea, text)
Returns: bytea
Language: C
pg_hmac
Function: public.hmac(text, text, text)
Returns: bytea
Language: C
pg_hmac
Function: public.hs_concat(public.hstore, public.hstore)
Returns: hstore
Language: C
hstore_concat
Function: public.hs_contained(public.hstore, public.hstore)
Returns: boolean
Language: C
hstore_contained
Function: public.hs_contains(public.hstore, public.hstore)
Returns: boolean
Language: C
hstore_contains
Function: public.hstore(record)
Returns: hstore
Language: C
hstore_from_record
Function: public.hstore(text, text)
Returns: hstore
Language: C
hstore_from_text
Function: public.hstore(text[])
Returns: hstore
Language: C
hstore_from_array
Function: public.hstore(text[], text[])
Returns: hstore
Language: C
hstore_from_arrays
Function: public.hstore_cmp(public.hstore, public.hstore)
Returns: integer
Language: C
hstore_cmp
Function: public.hstore_eq(public.hstore, public.hstore)
Returns: boolean
Language: C
hstore_eq
Function: public.hstore_ge(public.hstore, public.hstore)
Returns: boolean
Language: C
hstore_ge
Function: public.hstore_gt(public.hstore, public.hstore)
Returns: boolean
Language: C
hstore_gt
Function: public.hstore_hash(public.hstore)
Returns: integer
Language: C
hstore_hash
Function: public.hstore_in(cstring)
Returns: hstore
Language: C
hstore_in
Function: public.hstore_le(public.hstore, public.hstore)
Returns: boolean
Language: C
hstore_le
Function: public.hstore_lt(public.hstore, public.hstore)
Returns: boolean
Language: C
hstore_lt
Function: public.hstore_ne(public.hstore, public.hstore)
Returns: boolean
Language: C
hstore_ne
Function: public.hstore_out(public.hstore)
Returns: cstring
Language: C
hstore_out
Function: public.hstore_recv(internal)
Returns: hstore
Language: C
hstore_recv
Function: public.hstore_send(public.hstore)
Returns: bytea
Language: C
hstore_send
Function: public.hstore_to_array(public.hstore)
Returns: text[]
Language: C
hstore_to_array
Function: public.hstore_to_json(public.hstore)
Returns: json
Language: C
hstore_to_json
Function: public.hstore_to_json_loose(public.hstore)
Returns: json
Language: C
hstore_to_json_loose
Function: public.hstore_to_jsonb(public.hstore)
Returns: jsonb
Language: C
hstore_to_jsonb
Function: public.hstore_to_jsonb_loose(public.hstore)
Returns: jsonb
Language: C
hstore_to_jsonb_loose
Function: public.hstore_to_matrix(public.hstore)
Returns: text[]
Language: C
hstore_to_matrix
Function: public.hstore_version_diag(public.hstore)
Returns: integer
Language: C
hstore_version_diag
Function: public.icount(integer[])
Returns: integer
Language: C
icount
Function: public.idx(integer[], integer)
Returns: integer
Language: C
idx
Function: public.ingest_acq_marc()
Returns: trigger
Language: PLPGSQL
DECLARE value TEXT; atype TEXT; prov INT; pos INT; adef RECORD; xpath_string TEXT; BEGIN FOR adef IN SELECT *,tableoid FROM acq.lineitem_attr_definition LOOP SELECT relname::TEXT INTO atype FROM pg_class WHERE oid = adef.tableoid; IF (atype NOT IN ('lineitem_usr_attr_definition','lineitem_local_attr_definition')) THEN IF (atype = 'lineitem_provider_attr_definition') THEN SELECT provider INTO prov FROM acq.lineitem_provider_attr_definition WHERE id = adef.id; CONTINUE WHEN NEW.provider IS NULL OR prov <> NEW.provider; END IF; IF (atype = 'lineitem_provider_attr_definition') THEN SELECT xpath INTO xpath_string FROM acq.lineitem_provider_attr_definition WHERE id = adef.id; ELSIF (atype = 'lineitem_marc_attr_definition') THEN SELECT xpath INTO xpath_string FROM acq.lineitem_marc_attr_definition WHERE id = adef.id; ELSIF (atype = 'lineitem_generated_attr_definition') THEN SELECT xpath INTO xpath_string FROM acq.lineitem_generated_attr_definition WHERE id = adef.id; END IF; xpath_string := REGEXP_REPLACE(xpath_string,$re$//?text\(\)$$re$,''); IF (adef.code = 'title' OR adef.code = 'author') THEN -- title and author should not be split -- FIXME: once oils_xpath can grok XPATH 2.0 functions, we can use -- string-join in the xpath and remove this special case SELECT extract_acq_marc_field(id, xpath_string, adef.remove) INTO value FROM acq.lineitem WHERE id = NEW.id; IF (value IS NOT NULL AND value <> '') THEN INSERT INTO acq.lineitem_attr (lineitem, definition, attr_type, attr_name, attr_value) VALUES (NEW.id, adef.id, atype, adef.code, value); END IF; ELSE pos := 1; LOOP -- each application of the regex may produce multiple values FOR value IN SELECT * FROM extract_acq_marc_field_set( NEW.id, xpath_string || '[' || pos || ']', adef.remove) LOOP IF (value IS NOT NULL AND value <> '') THEN INSERT INTO acq.lineitem_attr (lineitem, definition, attr_type, attr_name, attr_value) VALUES (NEW.id, adef.id, atype, adef.code, value); ELSE EXIT; END IF; END LOOP; IF NOT FOUND THEN EXIT; END IF; pos := pos + 1; END LOOP; END IF; END IF; END LOOP; RETURN NULL; END;
Function: public.intarray_del_elem(integer[], integer)
Returns: integer[]
Language: C
intarray_del_elem
Function: public.intarray_push_array(integer[], integer[])
Returns: integer[]
Language: C
intarray_push_array
Function: public.intarray_push_elem(integer[], integer)
Returns: integer[]
Language: C
intarray_push_elem
Function: public.integer_or_null(text)
Returns: text
Language: SQL
SELECT CASE WHEN $1 ~ E'^\\d+$' THEN $1 ELSE NULL END
Function: public.intset(integer)
Returns: integer[]
Language: C
intset
Function: public.intset_subtract(integer[], integer[])
Returns: integer[]
Language: C
intset_subtract
Function: public.intset_union_elem(integer[], integer)
Returns: integer[]
Language: C
intset_union_elem
Function: public.isdefined(public.hstore, text)
Returns: boolean
Language: C
hstore_defined
Function: public.isexists(public.hstore, text)
Returns: boolean
Language: C
hstore_exists
Function: public.last(anyelement)
Returns: anyelement
Language: INTERNAL
aggregate_dummy
Function: public.last_agg(anyelement, anyelement)
Returns: anyelement
Language: SQL
SELECT $2;
Function: public.latitude(public.earth)
Returns: double precision
Language: SQL
SELECT CASE WHEN cube_ll_coord($1, 3)/earth() < -1 THEN -90::float8 WHEN cube_ll_coord($1, 3)/earth() > 1 THEN 90::float8 ELSE degrees(asin(cube_ll_coord($1, 3)/earth())) END
Function: public.left_trunc(text, integer)
Returns: text
Language: SQL
SELECT SUBSTRING($1,$2);
Function: public.levenshtein(text, text)
Returns: integer
Language: C
levenshtein
Function: public.levenshtein(text, text, integer, integer, integer)
Returns: integer
Language: C
levenshtein_with_costs
Function: public.levenshtein_less_equal(text, text, integer)
Returns: integer
Language: C
levenshtein_less_equal
Function: public.levenshtein_less_equal(text, text, integer, integer, integer, integer)
Returns: integer
Language: C
levenshtein_less_equal_with_costs
Function: public.ll_to_earth(double precision, double precision)
Returns: earth
Language: SQL
SELECT cube(cube(cube(earth()*cos(radians($1))*cos(radians($2))),earth()*cos(radians($1))*sin(radians($2))),earth()*sin(radians($1)))::earth
Function: public.longitude(public.earth)
Returns: double precision
Language: SQL
SELECT degrees(atan2(cube_ll_coord($1, 2), cube_ll_coord($1, 1)))
Function: public.lowercase(text)
Returns: text
Language: PLPERLU
return lc(shift);
Function: public.metaphone(text, integer)
Returns: text
Language: C
metaphone
Function: public.naco_normalize(text)
Returns: text
Language: SQL
SELECT public.naco_normalize($1,'');
Function: public.naco_normalize(text, text)
Returns: text
Language: PLPERLU
use strict; use Unicode::Normalize; use Encode; my $str = shift; my $sf = shift; # Apply NACO normalization to input string; based on # https://www.loc.gov/aba/pcc/naco/documents/SCA_PccNormalization_Final_revised.pdf # # Note that unlike a strict reading of the NACO normalization rules, # output is returned as lowercase instead of uppercase for compatibility # with previous versions of the Evergreen naco_normalize routine. # Convert to upper-case first; even though final output will be lowercase, doing this will # ensure that the German eszett (ß) and certain ligatures (ff, fi, ffl, etc.) will be handled correctly. # If there are any bugs in Perl's implementation of upcasing, they will be passed through here. $str = uc $str; # remove non-filing strings $str =~ s/\x{0098}.*?\x{009C}//g; # Replace curly single and double quote-like characters with straight single and double quotes $str =~ s/[\x{2018}\x{2019}\x{201B}\x{FF07}\x{201A}]/\x{0027}/g; $str =~ s/[\x{201C}\x{201D}\x{201F}\x{FF0C}\x{201E}\x{2E42}]/\x{0022}/g; $str = NFKD($str); # additional substitutions - 3.6. $str =~ s/\x{00C6}/AE/g; $str =~ s/\x{00DE}/TH/g; $str =~ s/\x{0152}/OE/g; $str =~ tr/\x{0110}\x{00D0}\x{00D8}\x{0141}\x{2113}\x{02BB}\x{02BC}]['/DDOLl/d; # transformations based on Unicode category codes $str =~ s/[\p{Cc}\p{Cf}\p{Co}\p{Cs}\p{Lm}\p{Mc}\p{Me}\p{Mn}]//g; if ($sf && $sf =~ /^a/o) { my $commapos = index($str, ','); if ($commapos > -1) { if ($commapos != length($str) - 1) { $str =~ s/,/\x07/; # preserve first comma } } } # since we've stripped out the control characters, we can now # use a few as placeholders temporarily $str =~ tr/+&@\x{266D}\x{266F}#/\x01\x02\x03\x04\x05\x06/; $str =~ s/[\p{Pc}\p{Pd}\p{Pe}\p{Pf}\p{Pi}\p{Po}\p{Ps}\p{Sk}\p{Sm}\p{So}\p{Zl}\p{Zp}\p{Zs}]/ /g; $str =~ tr/\x01\x02\x03\x04\x05\x06\x07/+&@\x{266D}\x{266F}#,/; # decimal digits $str =~ tr/\x{0660}-\x{0669}\x{06F0}-\x{06F9}\x{07C0}-\x{07C9}\x{0966}-\x{096F}\x{09E6}-\x{09EF}\x{0A66}-\x{0A6F}\x{0AE6}-\x{0AEF}\x{0B66}-\x{0B6F}\x{0BE6}-\x{0BEF}\x{0C66}-\x{0C6F}\x{0CE6}-\x{0CEF}\x{0D66}-\x{0D6F}\x{0E50}-\x{0E59}\x{0ED0}-\x{0ED9}\x{0F20}-\x{0F29}\x{1040}-\x{1049}\x{1090}-\x{1099}\x{17E0}-\x{17E9}\x{1810}-\x{1819}\x{1946}-\x{194F}\x{19D0}-\x{19D9}\x{1A80}-\x{1A89}\x{1A90}-\x{1A99}\x{1B50}-\x{1B59}\x{1BB0}-\x{1BB9}\x{1C40}-\x{1C49}\x{1C50}-\x{1C59}\x{A620}-\x{A629}\x{A8D0}-\x{A8D9}\x{A900}-\x{A909}\x{A9D0}-\x{A9D9}\x{AA50}-\x{AA59}\x{ABF0}-\x{ABF9}\x{FF10}-\x{FF19}/0-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-9/; # intentionally skipping step 8 of the NACO algorithm; if the string # gets normalized away, that's fine. # leading and trailing spaces $str =~ s/\s+/ /g; $str =~ s/^\s+//; $str =~ s/\s+$//g; return lc $str;
Function: public.naco_normalize_keep_comma(text)
Returns: text
Language: SQL
SELECT public.naco_normalize($1,'a');
Function: public.non_filing_normalize(text, "char")
Returns: text
Language: SQL
SELECT SUBSTRING( REGEXP_REPLACE( REGEXP_REPLACE( $1, E'\W*$', '' ), ' ', ' ' ), CASE WHEN $2::INT NOT BETWEEN 48 AND 57 THEN 1 ELSE $2::TEXT::INT + 1 END );
Function: public.normalize_space(text)
Returns: text
Language: SQL
SELECT regexp_replace(regexp_replace(regexp_replace($1, E'\\n', ' ', 'g'), E'(?:^\\s+)|(\\s+$)', '', 'g'), E'\\s+', ' ', 'g');
Function: public.oils_tsearch2()
Returns: trigger
Language: PLPGSQL
DECLARE normalizer RECORD; value TEXT := ''; temp_vector TEXT := ''; ts_rec RECORD; cur_weight "char"; BEGIN value := NEW.value; NEW.index_vector = ''::tsvector; IF TG_TABLE_NAME::TEXT ~ 'field_entry$' THEN FOR normalizer IN SELECT n.func AS func, n.param_count AS param_count, m.params AS params FROM config.index_normalizer n JOIN config.metabib_field_index_norm_map m ON (m.norm = n.id) WHERE field = NEW.field AND m.pos < 0 ORDER BY m.pos LOOP EXECUTE 'SELECT ' || normalizer.func || '(' || quote_literal( value ) || CASE WHEN normalizer.param_count > 0 THEN ',' || REPLACE(REPLACE(BTRIM(normalizer.params,'[]'),E'\'',E'\\\''),E'"',E'\'') ELSE '' END || ')' INTO value; END LOOP; NEW.value = value; FOR normalizer IN SELECT n.func AS func, n.param_count AS param_count, m.params AS params FROM config.index_normalizer n JOIN config.metabib_field_index_norm_map m ON (m.norm = n.id) WHERE field = NEW.field AND m.pos >= 0 ORDER BY m.pos LOOP EXECUTE 'SELECT ' || normalizer.func || '(' || quote_literal( value ) || CASE WHEN normalizer.param_count > 0 THEN ',' || REPLACE(REPLACE(BTRIM(normalizer.params,'[]'),E'\'',E'\\\''),E'"',E'\'') ELSE '' END || ')' INTO value; END LOOP; END IF; IF TG_TABLE_NAME::TEXT ~ 'browse_entry$' THEN value := ARRAY_TO_STRING( evergreen.regexp_split_to_array(value, E'\\W+'), ' ' ); value := public.search_normalize(value); NEW.index_vector = to_tsvector(TG_ARGV[0]::regconfig, value); ELSIF TG_TABLE_NAME::TEXT ~ 'field_entry$' THEN FOR ts_rec IN SELECT DISTINCT m.ts_config, m.index_weight FROM config.metabib_class_ts_map m LEFT JOIN metabib.record_attr_vector_list r ON (r.source = NEW.source) LEFT JOIN config.coded_value_map ccvm ON ( ccvm.ctype IN ('item_lang', 'language') AND ccvm.code = m.index_lang AND r.vlist @> intset(ccvm.id) ) WHERE m.field_class = TG_ARGV[0] AND m.active AND (m.always OR NOT EXISTS (SELECT 1 FROM config.metabib_field_ts_map WHERE metabib_field = NEW.field)) AND (m.index_lang IS NULL OR ccvm.id IS NOT NULL) UNION SELECT DISTINCT m.ts_config, m.index_weight FROM config.metabib_field_ts_map m LEFT JOIN metabib.record_attr_vector_list r ON (r.source = NEW.source) LEFT JOIN config.coded_value_map ccvm ON ( ccvm.ctype IN ('item_lang', 'language') AND ccvm.code = m.index_lang AND r.vlist @> intset(ccvm.id) ) WHERE m.metabib_field = NEW.field AND m.active AND (m.index_lang IS NULL OR ccvm.id IS NOT NULL) ORDER BY index_weight ASC LOOP IF cur_weight IS NOT NULL AND cur_weight != ts_rec.index_weight THEN NEW.index_vector = NEW.index_vector || setweight(temp_vector::tsvector,cur_weight); temp_vector = ''; END IF; cur_weight = ts_rec.index_weight; SELECT INTO temp_vector temp_vector || ' ' || to_tsvector(ts_rec.ts_config::regconfig, value)::TEXT; END LOOP; NEW.index_vector = NEW.index_vector || setweight(temp_vector::tsvector,cur_weight); ELSE NEW.index_vector = to_tsvector(TG_ARGV[0]::regconfig, value); END IF; RETURN NEW; END;
Function: public.pgp_armor_headers(value text)
Returns: SET OF record
Language: C
pgp_armor_headers
Function: public.pgp_key_id(bytea)
Returns: text
Language: C
pgp_key_id_w
Function: public.pgp_pub_decrypt(bytea, bytea)
Returns: text
Language: C
pgp_pub_decrypt_text
Function: public.pgp_pub_decrypt(bytea, bytea, text)
Returns: text
Language: C
pgp_pub_decrypt_text
Function: public.pgp_pub_decrypt(bytea, bytea, text, text)
Returns: text
Language: C
pgp_pub_decrypt_text
Function: public.pgp_pub_decrypt_bytea(bytea, bytea)
Returns: bytea
Language: C
pgp_pub_decrypt_bytea
Function: public.pgp_pub_decrypt_bytea(bytea, bytea, text)
Returns: bytea
Language: C
pgp_pub_decrypt_bytea
Function: public.pgp_pub_decrypt_bytea(bytea, bytea, text, text)
Returns: bytea
Language: C
pgp_pub_decrypt_bytea
Function: public.pgp_pub_encrypt(text, bytea)
Returns: bytea
Language: C
pgp_pub_encrypt_text
Function: public.pgp_pub_encrypt(text, bytea, text)
Returns: bytea
Language: C
pgp_pub_encrypt_text
Function: public.pgp_pub_encrypt_bytea(bytea, bytea)
Returns: bytea
Language: C
pgp_pub_encrypt_bytea
Function: public.pgp_pub_encrypt_bytea(bytea, bytea, text)
Returns: bytea
Language: C
pgp_pub_encrypt_bytea
Function: public.pgp_sym_decrypt(bytea, text)
Returns: text
Language: C
pgp_sym_decrypt_text
Function: public.pgp_sym_decrypt(bytea, text, text)
Returns: text
Language: C
pgp_sym_decrypt_text
Function: public.pgp_sym_decrypt_bytea(bytea, text)
Returns: bytea
Language: C
pgp_sym_decrypt_bytea
Function: public.pgp_sym_decrypt_bytea(bytea, text, text)
Returns: bytea
Language: C
pgp_sym_decrypt_bytea
Function: public.pgp_sym_encrypt(text, text)
Returns: bytea
Language: C
pgp_sym_encrypt_text
Function: public.pgp_sym_encrypt(text, text, text)
Returns: bytea
Language: C
pgp_sym_encrypt_text
Function: public.pgp_sym_encrypt_bytea(bytea, text)
Returns: bytea
Language: C
pgp_sym_encrypt_bytea
Function: public.pgp_sym_encrypt_bytea(bytea, text, text)
Returns: bytea
Language: C
pgp_sym_encrypt_bytea
Function: public.populate_record(anyelement, public.hstore)
Returns: anyelement
Language: C
hstore_populate_record
Function: public.querytree(public.query_int)
Returns: text
Language: C
querytree
Function: public.rboolop(public.query_int, integer[])
Returns: boolean
Language: C
boolean operation with array
rboolop
Function: public.remove_commas(text)
Returns: text
Language: SQL
SELECT regexp_replace($1, ',', '', 'g');
Function: public.remove_diacritics(text)
Returns: text
Language: PLPERLU
use Unicode::Normalize; my $x = NFD(shift); $x =~ s/\pM+//go; return $x;
Function: public.remove_paren_substring(text)
Returns: text
Language: SQL
SELECT regexp_replace($1, $$\([^)]+\)$$, '', 'g');
Function: public.remove_whitespace(text)
Returns: text
Language: SQL
SELECT regexp_replace(normalize_space($1), E'\\s+', '', 'g');
Function: public.right_trunc(text, integer)
Returns: text
Language: SQL
SELECT SUBSTRING($1,1,$2);
Function: public.search_normalize(text)
Returns: text
Language: SQL
SELECT public.search_normalize($1,'');
Function: public.search_normalize(text, text)
Returns: text
Language: PLPERLU
use strict; use Unicode::Normalize; use Encode; my $str = shift; my $sf = shift; # Apply NACO normalization to input string; based on # https://www.loc.gov/aba/pcc/naco/documents/SCA_PccNormalization_Final_revised.pdf # # Note that unlike a strict reading of the NACO normalization rules, # output is returned as lowercase instead of uppercase for compatibility # with previous versions of the Evergreen naco_normalize routine. # Convert to upper-case first; even though final output will be lowercase, doing this will # ensure that the German eszett (ß) and certain ligatures (ff, fi, ffl, etc.) will be handled correctly. # If there are any bugs in Perl's implementation of upcasing, they will be passed through here. $str = uc $str; # remove non-filing strings $str =~ s/\x{0098}.*?\x{009C}//g; # Replace curly single and double quote-like characters with straight single and double quotes $str =~ s/[\x{2018}\x{2019}\x{201B}\x{FF07}\x{201A}]/\x{0027}/g; $str =~ s/[\x{201C}\x{201D}\x{201F}\x{FF0C}\x{201E}\x{2E42}]/\x{0022}/g; $str = NFKD($str); # additional substitutions - 3.6. $str =~ s/\x{00C6}/AE/g; $str =~ s/\x{00DE}/TH/g; $str =~ s/\x{0152}/OE/g; $str =~ tr/\x{0110}\x{00D0}\x{00D8}\x{0141}\x{2113}\x{02BB}\x{02BC}][/DDOLl/d; # transformations based on Unicode category codes $str =~ s/[\p{Cc}\p{Cf}\p{Co}\p{Cs}\p{Lm}\p{Mc}\p{Me}\p{Mn}]//g; if ($sf && $sf =~ /^a/o) { my $commapos = index($str, ','); if ($commapos > -1) { if ($commapos != length($str) - 1) { $str =~ s/,/\x07/; # preserve first comma } } } # since we've stripped out the control characters, we can now # use a few as placeholders temporarily $str =~ tr/+&@\x{266D}\x{266F}#/\x01\x02\x03\x04\x05\x06/; $str =~ s/[\p{Pc}\p{Pd}\p{Pe}\p{Pf}\p{Pi}\p{Po}\p{Ps}\p{Sk}\p{Sm}\p{So}\p{Zl}\p{Zp}\p{Zs}]/ /g; $str =~ tr/\x01\x02\x03\x04\x05\x06\x07/+&@\x{266D}\x{266F}#,/; # decimal digits $str =~ tr/\x{0660}-\x{0669}\x{06F0}-\x{06F9}\x{07C0}-\x{07C9}\x{0966}-\x{096F}\x{09E6}-\x{09EF}\x{0A66}-\x{0A6F}\x{0AE6}-\x{0AEF}\x{0B66}-\x{0B6F}\x{0BE6}-\x{0BEF}\x{0C66}-\x{0C6F}\x{0CE6}-\x{0CEF}\x{0D66}-\x{0D6F}\x{0E50}-\x{0E59}\x{0ED0}-\x{0ED9}\x{0F20}-\x{0F29}\x{1040}-\x{1049}\x{1090}-\x{1099}\x{17E0}-\x{17E9}\x{1810}-\x{1819}\x{1946}-\x{194F}\x{19D0}-\x{19D9}\x{1A80}-\x{1A89}\x{1A90}-\x{1A99}\x{1B50}-\x{1B59}\x{1BB0}-\x{1BB9}\x{1C40}-\x{1C49}\x{1C50}-\x{1C59}\x{A620}-\x{A629}\x{A8D0}-\x{A8D9}\x{A900}-\x{A909}\x{A9D0}-\x{A9D9}\x{AA50}-\x{AA59}\x{ABF0}-\x{ABF9}\x{FF10}-\x{FF19}/0-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-90-9/; # intentionally skipping step 8 of the NACO algorithm; if the string # gets normalized away, that's fine. # leading and trailing spaces $str =~ s/\s+/ /g; $str =~ s/^\s+//; $str =~ s/\s+$//g; return lc $str;
Function: public.search_normalize_keep_comma(text)
Returns: text
Language: SQL
SELECT public.search_normalize($1,'a');
Function: public.sec_to_gc(double precision)
Returns: double precision
Language: SQL
SELECT CASE WHEN $1 < 0 THEN 0::float8 WHEN $1/(2*earth()) > 1 THEN pi()*earth() ELSE 2*earth()*asin($1/(2*earth())) END
Function: public.set_limit(real)
Returns: real
Language: C
set_limit
Function: public.show_limit()
Returns: real
Language: C
show_limit
Function: public.show_trgm(text)
Returns: text[]
Language: C
show_trgm
Function: public.similarity(text, text)
Returns: real
Language: C
similarity
Function: public.similarity_dist(text, text)
Returns: real
Language: C
similarity_dist
Function: public.similarity_op(text, text)
Returns: boolean
Language: C
similarity_op
Function: public.skeys(public.hstore)
Returns: SET OF text
Language: C
hstore_skeys
Function: public.slice(public.hstore, text[])
Returns: hstore
Language: C
hstore_slice_to_hstore
Function: public.slice_array(public.hstore, text[])
Returns: text[]
Language: C
hstore_slice_to_array
Function: public.sort(integer[])
Returns: integer[]
Language: C
sort
Function: public.sort(integer[], text)
Returns: integer[]
Language: C
sort
Function: public.sort_asc(integer[])
Returns: integer[]
Language: C
sort_asc
Function: public.sort_desc(integer[])
Returns: integer[]
Language: C
sort_desc
Function: public.soundex(text)
Returns: text
Language: C
soundex
Function: public.split_date_range(text)
Returns: text
Language: SQL
SELECT REGEXP_REPLACE( $1, E'(\\d{4})-(\\d{4})', E'\\1 \\2', 'g' );
Function: public.subarray(integer[], integer)
Returns: integer[]
Language: C
subarray
Function: public.subarray(integer[], integer, integer)
Returns: integer[]
Language: C
subarray
Function: public.svals(public.hstore)
Returns: SET OF text
Language: C
hstore_svals
Function: public.tconvert(text, text)
Returns: hstore
Language: C
hstore_from_text
Function: public.text_concat(text, text)
Returns: text
Language: SQL
SELECT CASE WHEN $1 IS NULL THEN $2 WHEN $2 IS NULL THEN $1 ELSE $1 || ' ' || $2 END;
Function: public.text_soundex(text)
Returns: text
Language: C
soundex
Function: public.translate_isbn1013(text)
Returns: text
Language: PLPERLU
The translate_isbn1013 function takes an input ISBN and returns the following in a single space-delimited string if the input ISBN is valid: - The normalized input ISBN (hyphens stripped) - The normalized input ISBN with a fixed checksum if the checksum was bad - The ISBN converted to its ISBN10 or ISBN13 counterpart, if possible
use Business::ISBN; use strict; use warnings; # For each ISBN found in a single string containing a set of ISBNs: # * Normalize an incoming ISBN to have the correct checksum and no hyphens # * Convert an incoming ISBN10 or ISBN13 to its counterpart and return my $input = shift; my $output = ''; foreach my $word (split(/\s/, $input)) { my $isbn = Business::ISBN->new($word); # First check the checksum; if it is not valid, fix it and add the original # bad-checksum ISBN to the output if ($isbn && $isbn->is_valid_checksum() == Business::ISBN::BAD_CHECKSUM) { $output .= $isbn->isbn() . " "; $isbn->fix_checksum(); } # If we now have a valid ISBN, convert it to its counterpart ISBN10/ISBN13 # and add the normalized original ISBN to the output if ($isbn && $isbn->is_valid()) { my $isbn_xlated = ($isbn->type eq "ISBN13") ? $isbn->as_isbn10 : $isbn->as_isbn13; $output .= $isbn->isbn . " "; # If we successfully converted the ISBN to its counterpart, add the # converted ISBN to the output as well $output .= ($isbn_xlated->isbn . " ") if ($isbn_xlated); } } return $output if $output; # If there were no valid ISBNs, just return the raw input return $input;
Function: public.unaccent(regdictionary, text)
Returns: text
Language: C
unaccent_dict
Function: public.unaccent(text)
Returns: text
Language: C
unaccent_dict
Function: public.unaccent_init(internal)
Returns: internal
Language: C
unaccent_init
Function: public.unaccent_lexize(internal, internal, internal, internal)
Returns: internal
Language: C
unaccent_lexize
Function: public.uniq(integer[])
Returns: integer[]
Language: C
uniq
Function: public.uppercase(text)
Returns: text
Language: PLPERLU
return uc(shift);
Function: public.word_similarity(text, text)
Returns: real
Language: C
word_similarity
Function: public.word_similarity_commutator_op(text, text)
Returns: boolean
Language: C
word_similarity_commutator_op
Function: public.word_similarity_dist_commutator_op(text, text)
Returns: real
Language: C
word_similarity_dist_commutator_op
Function: public.word_similarity_dist_op(text, text)
Returns: real
Language: C
word_similarity_dist_op
Function: public.word_similarity_op(text, text)
Returns: boolean
Language: C
word_similarity_op
Function: public.xml_encode_special_chars(text)
Returns: text
Language: C
xml_encode_special_chars
Function: public.xml_valid(text)
Returns: boolean
Language: INTERNAL
xml_is_well_formed
Function: public.xpath_bool(text, text)
Returns: boolean
Language: C
xpath_bool
Function: public.xpath_list(text, text)
Returns: text
Language: SQL
SELECT xpath_list($1,$2,',')
Function: public.xpath_list(text, text, text)
Returns: text
Language: C
xpath_list
Function: public.xpath_nodeset(text, text)
Returns: text
Language: SQL
SELECT xpath_nodeset($1,$2,'','')
Function: public.xpath_nodeset(text, text, text)
Returns: text
Language: SQL
SELECT xpath_nodeset($1,$2,'',$3)
Function: public.xpath_nodeset(text, text, text, text)
Returns: text
Language: C
xpath_nodeset
Function: public.xpath_number(text, text)
Returns: real
Language: C
xpath_number
Function: public.xpath_string(text, text)
Returns: text
Language: C
xpath_string
Function: public.xpath_table(text, text, text, text, text)
Returns: SET OF record
Language: C
xpath_table
Function: public.xslt_process(text, text)
Returns: text
Language: C
xslt_process
Function: public.xslt_process(text, text, text)
Returns: text
Language: C
xslt_process
Schema query
Contains tables designed to represent user-defined queries for reports and the like.
Table: query.bind_variable
F-Key | Name | Type | Description |
---|---|---|---|
name | text | PRIMARY KEY | |
type | text | NOT NULL | |
description | text | NOT NULL | |
default_value | text | ||
label | text | NOT NULL |
Name | Constraint |
---|---|
bind_variable_type | CHECK ((type = ANY (ARRAY['string'::text, 'number'::text, 'string_list'::text, 'number_list'::text]))) |
Tables referencing this one via Foreign Key Constraints:
Table: query.case_branch
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
query.expression.id | parent_expr | integer | UNIQUE#1 NOT NULL |
seq_no | integer | UNIQUE#1 NOT NULL | |
query.expression.id | condition | integer | |
query.expression.id | result | integer | NOT NULL |
Table: query.datatype
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
datatype_name | text | UNIQUE NOT NULL | |
is_numeric | boolean | NOT NULL DEFAULT false | |
is_composite | boolean | NOT NULL DEFAULT false |
Name | Constraint |
---|---|
qdt_comp_not_num | CHECK (((is_numeric IS FALSE) OR (is_composite IS FALSE))) |
Tables referencing this one via Foreign Key Constraints:
View: query.expr_xbet
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
parenthesize | boolean | ||
parent_expr | integer | ||
seq_no | integer | ||
left_operand | integer | ||
negate | boolean |
SELECT expression.id , expression.parenthesize , expression.parent_expr , expression.seq_no , expression.left_operand , expression.negate FROM query.expression WHERE (expression.type = 'xbet'::text);
View: query.expr_xbind
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
parenthesize | boolean | ||
parent_expr | integer | ||
seq_no | integer | ||
bind_variable | text |
SELECT expression.id , expression.parenthesize , expression.parent_expr , expression.seq_no , expression.bind_variable FROM query.expression WHERE (expression.type = 'xbind'::text);
View: query.expr_xbool
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
parenthesize | boolean | ||
parent_expr | integer | ||
seq_no | integer | ||
literal | text | ||
negate | boolean |
SELECT expression.id , expression.parenthesize , expression.parent_expr , expression.seq_no , expression.literal , expression.negate FROM query.expression WHERE (expression.type = 'xbool'::text);
View: query.expr_xcase
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
parenthesize | boolean | ||
parent_expr | integer | ||
seq_no | integer | ||
left_operand | integer | ||
negate | boolean |
SELECT expression.id , expression.parenthesize , expression.parent_expr , expression.seq_no , expression.left_operand , expression.negate FROM query.expression WHERE (expression.type = 'xcase'::text);
View: query.expr_xcast
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
parenthesize | boolean | ||
parent_expr | integer | ||
seq_no | integer | ||
left_operand | integer | ||
cast_type | integer | ||
negate | boolean |
SELECT expression.id , expression.parenthesize , expression.parent_expr , expression.seq_no , expression.left_operand , expression.cast_type , expression.negate FROM query.expression WHERE (expression.type = 'xcast'::text);
View: query.expr_xcol
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
parenthesize | boolean | ||
parent_expr | integer | ||
seq_no | integer | ||
table_alias | text | ||
column_name | text | ||
negate | boolean |
SELECT expression.id , expression.parenthesize , expression.parent_expr , expression.seq_no , expression.table_alias , expression.column_name , expression.negate FROM query.expression WHERE (expression.type = 'xcol'::text);
View: query.expr_xex
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
parenthesize | boolean | ||
parent_expr | integer | ||
seq_no | integer | ||
subquery | integer | ||
negate | boolean |
SELECT expression.id , expression.parenthesize , expression.parent_expr , expression.seq_no , expression.subquery , expression.negate FROM query.expression WHERE (expression.type = 'xex'::text);
View: query.expr_xfunc
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
parenthesize | boolean | ||
parent_expr | integer | ||
seq_no | integer | ||
column_name | text | ||
function_id | integer | ||
negate | boolean |
SELECT expression.id , expression.parenthesize , expression.parent_expr , expression.seq_no , expression.column_name , expression.function_id , expression.negate FROM query.expression WHERE (expression.type = 'xfunc'::text);
View: query.expr_xin
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
parenthesize | boolean | ||
parent_expr | integer | ||
seq_no | integer | ||
left_operand | integer | ||
subquery | integer | ||
negate | boolean |
SELECT expression.id , expression.parenthesize , expression.parent_expr , expression.seq_no , expression.left_operand , expression.subquery , expression.negate FROM query.expression WHERE (expression.type = 'xin'::text);
View: query.expr_xisnull
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
parenthesize | boolean | ||
parent_expr | integer | ||
seq_no | integer | ||
left_operand | integer | ||
negate | boolean |
SELECT expression.id , expression.parenthesize , expression.parent_expr , expression.seq_no , expression.left_operand , expression.negate FROM query.expression WHERE (expression.type = 'xisnull'::text);
View: query.expr_xnull
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
parenthesize | boolean | ||
parent_expr | integer | ||
seq_no | integer | ||
negate | boolean |
SELECT expression.id , expression.parenthesize , expression.parent_expr , expression.seq_no , expression.negate FROM query.expression WHERE (expression.type = 'xnull'::text);
View: query.expr_xnum
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
parenthesize | boolean | ||
parent_expr | integer | ||
seq_no | integer | ||
literal | text |
SELECT expression.id , expression.parenthesize , expression.parent_expr , expression.seq_no , expression.literal FROM query.expression WHERE (expression.type = 'xnum'::text);
View: query.expr_xop
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
parenthesize | boolean | ||
parent_expr | integer | ||
seq_no | integer | ||
left_operand | integer | ||
operator | text | ||
right_operand | integer | ||
negate | boolean |
SELECT expression.id , expression.parenthesize , expression.parent_expr , expression.seq_no , expression.left_operand , expression.operator , expression.right_operand , expression.negate FROM query.expression WHERE (expression.type = 'xop'::text);
View: query.expr_xser
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
parenthesize | boolean | ||
parent_expr | integer | ||
seq_no | integer | ||
operator | text | ||
negate | boolean |
SELECT expression.id , expression.parenthesize , expression.parent_expr , expression.seq_no , expression.operator , expression.negate FROM query.expression WHERE (expression.type = 'xser'::text);
View: query.expr_xstr
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
parenthesize | boolean | ||
parent_expr | integer | ||
seq_no | integer | ||
literal | text |
SELECT expression.id , expression.parenthesize , expression.parent_expr , expression.seq_no , expression.literal FROM query.expression WHERE (expression.type = 'xstr'::text);
View: query.expr_xsubq
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
parenthesize | boolean | ||
parent_expr | integer | ||
seq_no | integer | ||
subquery | integer | ||
negate | boolean |
SELECT expression.id , expression.parenthesize , expression.parent_expr , expression.seq_no , expression.subquery , expression.negate FROM query.expression WHERE (expression.type = 'xsubq'::text);
Table: query.expression
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
type | text | NOT NULL | |
parenthesize | boolean | NOT NULL DEFAULT false | |
query.expression.id | parent_expr | integer | |
seq_no | integer | NOT NULL DEFAULT 1 | |
literal | text | ||
table_alias | text | ||
column_name | text | ||
query.expression.id | left_operand | integer | |
operator | text | ||
query.expression.id | right_operand | integer | |
query.function_sig.id | function_id | integer | |
query.stored_query.id | subquery | integer | |
query.datatype.id | cast_type | integer | |
negate | boolean | NOT NULL DEFAULT false | |
query.bind_variable.name | bind_variable | text |
Name | Constraint |
---|---|
expression_type | CHECK ((type = ANY (ARRAY['xbet'::text, 'xbind'::text, 'xbool'::text, 'xcase'::text, 'xcast'::text, 'xcol'::text, 'xex'::text, 'xfunc'::text, 'xin'::text, 'xisnull'::text, 'xnull'::text, 'xnum'::text, 'xop'::text, 'xser'::text, 'xstr'::text, 'xsubq'::text]))) |
Tables referencing this one via Foreign Key Constraints:
Table: query.from_relation
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
type | text | NOT NULL | |
table_name | text | ||
class_name | text | ||
query.stored_query.id | subquery | integer | |
query.expression.id | function_call | integer | |
table_alias | text | ||
query.from_relation.id | parent_relation | integer | |
seq_no | integer | NOT NULL DEFAULT 1 | |
join_type | text | ||
query.expression.id | on_clause | integer |
Name | Constraint |
---|---|
good_join_type | CHECK (((join_type IS NULL) OR (join_type = ANY (ARRAY['INNER'::text, 'LEFT'::text, 'RIGHT'::text, 'FULL'::text])))) |
join_or_core | CHECK ((((parent_relation IS NULL) AND (join_type IS NULL) AND (on_clause IS NULL)) OR ((parent_relation IS NOT NULL) AND (join_type IS NOT NULL) AND (on_clause IS NOT NULL)))) |
relation_type | CHECK ((type = ANY (ARRAY['RELATION'::text, 'SUBQUERY'::text, 'FUNCTION'::text]))) |
Tables referencing this one via Foreign Key Constraints:
Table: query.function_param_def
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
query.function_sig.id | function_id | integer | UNIQUE#1 NOT NULL |
seq_no | integer | UNIQUE#1 NOT NULL | |
query.datatype.id | datatype | integer | NOT NULL |
Name | Constraint |
---|---|
qfpd_pos_seq_no | CHECK ((seq_no > 0)) |
Table: query.function_sig
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
function_name | text | NOT NULL | |
query.datatype.id | return_type | integer | |
is_aggregate | boolean | NOT NULL DEFAULT false |
Name | Constraint |
---|---|
qfd_rtn_or_aggr | CHECK (((return_type IS NULL) OR (is_aggregate = false))) |
Tables referencing this one via Foreign Key Constraints:
query_function_sig_name_idx function_nameTable: query.order_by_item
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
query.stored_query.id | stored_query | integer | UNIQUE#1 NOT NULL |
seq_no | integer | UNIQUE#1 NOT NULL | |
query.expression.id | expression | integer | NOT NULL |
Table: query.query_sequence
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
query.stored_query.id | parent_query | integer | UNIQUE#1 NOT NULL |
seq_no | integer | UNIQUE#1 NOT NULL | |
query.stored_query.id | child_query | integer | NOT NULL |
Table: query.record_column
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
query.from_relation.id | from_relation | integer | UNIQUE#1 NOT NULL |
seq_no | integer | UNIQUE#1 NOT NULL | |
column_name | text | NOT NULL | |
query.datatype.id | column_type | integer | NOT NULL |
Table: query.select_item
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
query.stored_query.id | stored_query | integer | UNIQUE#1 NOT NULL |
seq_no | integer | UNIQUE#1 NOT NULL | |
query.expression.id | expression | integer | NOT NULL |
column_alias | text | ||
grouped_by | boolean | NOT NULL DEFAULT false |
Table: query.stored_query
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
type | text | NOT NULL | |
use_all | boolean | NOT NULL DEFAULT false | |
use_distinct | boolean | NOT NULL DEFAULT false | |
query.from_relation.id | from_clause | integer | |
query.expression.id | where_clause | integer | |
query.expression.id | having_clause | integer | |
query.expression.id | limit_count | integer | |
query.expression.id | offset_count | integer |
Name | Constraint |
---|---|
query_type | CHECK ((type = ANY (ARRAY['SELECT'::text, 'UNION'::text, 'INTERSECT'::text, 'EXCEPT'::text]))) |
Tables referencing this one via Foreign Key Constraints:
Table: query.subfield
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
query.datatype.id | composite_type | integer | UNIQUE#1 NOT NULL |
seq_no | integer | UNIQUE#1 NOT NULL | |
query.datatype.id | subfield_type | integer | NOT NULL |
Name | Constraint |
---|---|
qsf_pos_seq_no | CHECK ((seq_no > 0)) |
Schema rating
Table: rating.badge
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE#1 NOT NULL | |
description | text | ||
actor.org_unit.id | scope | integer | UNIQUE#1 NOT NULL |
weight | integer | NOT NULL DEFAULT 1 | |
horizon_age | interval | ||
importance_age | interval | ||
importance_interval | interval | NOT NULL DEFAULT '1 day'::interval | |
importance_scale | numeric | ||
recalc_interval | interval | NOT NULL DEFAULT '1 mon'::interval | |
attr_filter | text | ||
config.bib_source.id | src_filter | integer | |
config.circ_modifier.code | circ_mod_filter | text | |
asset.copy_location_group.id | loc_grp_filter | integer | |
rating.popularity_parameter.id | popularity_parameter | integer | NOT NULL |
fixed_rating | integer | ||
percentile | numeric | ||
discard | integer | NOT NULL | |
last_calc | timestamp with time zone |
Name | Constraint |
---|---|
badge_fixed_rating_check | CHECK (((fixed_rating IS NULL) OR ((fixed_rating >= '-5'::integer) AND (fixed_rating <= 5)))) |
badge_importance_scale_check | CHECK (((importance_scale IS NULL) OR (importance_scale > 0.0))) |
badge_percentile_check | CHECK (((percentile IS NULL) OR ((percentile >= 50.0) AND (percentile < 100.0)))) |
Tables referencing this one via Foreign Key Constraints:
View: rating.badge_with_orgs
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
name | text | ||
description | text | ||
scope | integer | ||
weight | integer | ||
horizon_age | interval | ||
importance_age | interval | ||
importance_interval | interval | ||
importance_scale | numeric | ||
recalc_interval | interval | ||
attr_filter | text | ||
src_filter | integer | ||
circ_mod_filter | text | ||
loc_grp_filter | integer | ||
popularity_parameter | integer | ||
fixed_rating | integer | ||
percentile | numeric | ||
discard | integer | ||
last_calc | timestamp with time zone | ||
orgs | integer[] |
WITH org_scope AS ( SELECT x.id , array_agg (x.tree) AS orgs FROM ( SELECT org_unit.id , (actor.org_unit_descendants (org_unit.id) ).id AS tree FROM actor.org_unit ) x GROUP BY x.id ) SELECT b.id , b.name , b.description , b.scope , b.weight , b.horizon_age , b.importance_age , b.importance_interval , b.importance_scale , b.recalc_interval , b.attr_filter , b.src_filter , b.circ_mod_filter , b.loc_grp_filter , b.popularity_parameter , b.fixed_rating , b.percentile , b.discard , b.last_calc , s.orgs FROM (rating.badge b JOIN org_scope s ON ( (b.scope = s.id) ) );
Table: rating.popularity_parameter
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | PRIMARY KEY | |
name | text | UNIQUE NOT NULL | |
description | text | ||
func | text | ||
require_horizon | boolean | NOT NULL DEFAULT false | |
require_importance | boolean | NOT NULL DEFAULT false | |
require_percentile | boolean | NOT NULL DEFAULT false |
Tables referencing this one via Foreign Key Constraints:
Table: rating.record_badge_score
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
biblio.record_entry.id | record | bigint | UNIQUE#1 NOT NULL |
rating.badge.id | badge | integer | UNIQUE#1 NOT NULL |
score | integer | NOT NULL |
Name | Constraint |
---|---|
record_badge_score_score_check | CHECK (((score >= '-5'::integer) AND (score <= 5))) |
Function: rating.bib_pub_age(value integer)
Returns: SET OF record
Language: PLPGSQL
DECLARE badge rating.badge_with_orgs%ROWTYPE; BEGIN SELECT * INTO badge FROM rating.badge_with_orgs WHERE id = badge_id; PERFORM rating.precalc_bibs_by_copy_or_uri(badge_id); SET LOCAL client_min_messages = error; DROP TABLE IF EXISTS precalc_bib_list; CREATE TEMP TABLE precalc_bib_list ON COMMIT DROP AS SELECT id FROM precalc_filter_bib_list INTERSECT SELECT id FROM precalc_bibs_by_copy_or_uri_list; RETURN QUERY SELECT pop.id AS bib, s.value::NUMERIC FROM precalc_bib_list pop JOIN metabib.record_sorter s ON ( s.source = pop.id AND s.attr = 'pubdate' AND s.value ~ '^\d+$' ) WHERE s.value::INT <= EXTRACT(YEAR FROM NOW())::INT; END;
Function: rating.bib_record_age(value integer)
Returns: SET OF record
Language: PLPGSQL
DECLARE badge rating.badge_with_orgs%ROWTYPE; BEGIN SELECT * INTO badge FROM rating.badge_with_orgs WHERE id = badge_id; PERFORM rating.precalc_bibs_by_copy_or_uri(badge_id); SET LOCAL client_min_messages = error; DROP TABLE IF EXISTS precalc_bib_list; CREATE TEMP TABLE precalc_bib_list ON COMMIT DROP AS SELECT id FROM precalc_filter_bib_list INTERSECT SELECT id FROM precalc_bibs_by_copy_or_uri_list; RETURN QUERY SELECT b.id, 1.0 / EXTRACT(EPOCH FROM AGE(b.create_date))::NUMERIC + 1.0 FROM precalc_bib_list pop JOIN biblio.record_entry b ON (b.id = pop.id); END;
Function: rating.checked_out_total_ratio(value integer)
Returns: SET OF record
Language: PLPGSQL
DECLARE badge rating.badge_with_orgs%ROWTYPE; BEGIN SELECT * INTO badge FROM rating.badge_with_orgs WHERE id = badge_id; PERFORM rating.precalc_bibs_by_copy(badge_id); DELETE FROM precalc_copy_filter_bib_list WHERE id NOT IN ( SELECT id FROM precalc_filter_bib_list INTERSECT SELECT id FROM precalc_bibs_by_copy_list ); ANALYZE precalc_copy_filter_bib_list; RETURN QUERY SELECT bib, SUM(checked_out)::NUMERIC / SUM(total)::NUMERIC FROM (SELECT cn.record AS bib, (cp.status = 1)::INT AS checked_out, 1 AS total FROM asset.copy cp JOIN precalc_copy_filter_bib_list c ON (cp.id = c.copy) JOIN asset.call_number cn ON (cn.id = cp.call_number) WHERE cn.owning_lib = ANY (badge.orgs) ) x GROUP BY 1; END;
Function: rating.circs_over_time(value integer)
Returns: SET OF record
Language: PLPGSQL
DECLARE badge rating.badge_with_orgs%ROWTYPE; iage INT := 1; iint INT := NULL; iscale NUMERIC := NULL; BEGIN SELECT * INTO badge FROM rating.badge_with_orgs WHERE id = badge_id; IF badge.horizon_age IS NULL THEN RAISE EXCEPTION 'Badge "%" with id % requires a horizon age but has none.', badge.name, badge.id; END IF; PERFORM rating.precalc_bibs_by_copy(badge_id); DELETE FROM precalc_copy_filter_bib_list WHERE id NOT IN ( SELECT id FROM precalc_filter_bib_list INTERSECT SELECT id FROM precalc_bibs_by_copy_list ); ANALYZE precalc_copy_filter_bib_list; iint := EXTRACT(EPOCH FROM badge.importance_interval); IF badge.importance_age IS NOT NULL THEN iage := (EXTRACT(EPOCH FROM badge.importance_age) / iint)::INT; END IF; -- if iscale is smaller than 1, scaling slope will be shallow ... BEWARE! iscale := COALESCE(badge.importance_scale, 1.0); RETURN QUERY SELECT bib, SUM( circs * GREATEST( iscale * (iage - cage), 1.0 )) FROM ( SELECT cn.record AS bib, (1 + EXTRACT(EPOCH FROM AGE(c.xact_start)) / iint)::INT AS cage, COUNT(c.id)::INT AS circs FROM action.circulation c JOIN precalc_copy_filter_bib_list cf ON (c.target_copy = cf.copy) JOIN asset.copy cp ON (cp.id = c.target_copy) JOIN asset.call_number cn ON (cn.id = cp.call_number) WHERE c.xact_start >= NOW() - badge.horizon_age AND cn.owning_lib = ANY (badge.orgs) AND c.phone_renewal IS FALSE -- we don't count renewals AND c.desk_renewal IS FALSE AND c.opac_renewal IS FALSE GROUP BY 1, 2 ) x GROUP BY 1; END;
Function: rating.copy_count(value integer)
Returns: SET OF record
Language: PLPGSQL
DECLARE badge rating.badge_with_orgs%ROWTYPE; BEGIN SELECT * INTO badge FROM rating.badge_with_orgs WHERE id = badge_id; PERFORM rating.precalc_bibs_by_copy(badge_id); DELETE FROM precalc_copy_filter_bib_list WHERE id NOT IN ( SELECT id FROM precalc_filter_bib_list INTERSECT SELECT id FROM precalc_bibs_by_copy_list ); ANALYZE precalc_copy_filter_bib_list; RETURN QUERY SELECT f.id::INT AS bib, COUNT(f.copy)::NUMERIC FROM precalc_copy_filter_bib_list f JOIN asset.copy cp ON (f.copy = cp.id) JOIN asset.call_number cn ON (cn.id = cp.call_number) WHERE cn.owning_lib = ANY (badge.orgs) GROUP BY 1; END;
Function: rating.current_circ_count(value integer)
Returns: SET OF record
Language: PLPGSQL
DECLARE badge rating.badge_with_orgs%ROWTYPE; BEGIN SELECT * INTO badge FROM rating.badge_with_orgs WHERE id = badge_id; PERFORM rating.precalc_bibs_by_copy(badge_id); DELETE FROM precalc_copy_filter_bib_list WHERE id NOT IN ( SELECT id FROM precalc_filter_bib_list INTERSECT SELECT id FROM precalc_bibs_by_copy_list ); ANALYZE precalc_copy_filter_bib_list; RETURN QUERY SELECT cn.record AS bib, COUNT(c.id)::NUMERIC AS circs FROM action.circulation c JOIN precalc_copy_filter_bib_list cf ON (c.target_copy = cf.copy) JOIN asset.copy cp ON (cp.id = c.target_copy) JOIN asset.call_number cn ON (cn.id = cp.call_number) WHERE c.checkin_time IS NULL AND cn.owning_lib = ANY (badge.orgs) GROUP BY 1; END;
Function: rating.current_hold_count(value integer)
Returns: SET OF record
Language: PLPGSQL
DECLARE badge rating.badge_with_orgs%ROWTYPE; BEGIN SELECT * INTO badge FROM rating.badge_with_orgs WHERE id = badge_id; PERFORM rating.precalc_bibs_by_copy(badge_id); DELETE FROM precalc_copy_filter_bib_list WHERE id NOT IN ( SELECT id FROM precalc_filter_bib_list INTERSECT SELECT id FROM precalc_bibs_by_copy_list ); ANALYZE precalc_copy_filter_bib_list; RETURN QUERY SELECT rhrr.bib_record AS bib, COUNT(DISTINCT h.id)::NUMERIC AS holds FROM action.hold_request h JOIN reporter.hold_request_record rhrr ON (rhrr.id = h.id) JOIN action.hold_copy_map m ON (m.hold = h.id) JOIN precalc_copy_filter_bib_list cf ON (rhrr.bib_record = cf.id AND m.target_copy = cf.copy) WHERE h.fulfillment_time IS NULL AND h.request_lib = ANY (badge.orgs) GROUP BY 1; END;
Function: rating.generic_fixed_rating_by_copy(value integer)
Returns: SET OF record
Language: PLPGSQL
BEGIN PERFORM rating.precalc_bibs_by_copy(badge_id); RETURN QUERY SELECT id, 1.0 FROM precalc_filter_bib_list INTERSECT SELECT id, 1.0 FROM precalc_bibs_by_copy_list; END;
Function: rating.generic_fixed_rating_by_copy_or_uri(value integer)
Returns: SET OF record
Language: PLPGSQL
BEGIN PERFORM rating.precalc_bibs_by_copy_or_uri(badge_id); RETURN QUERY (SELECT id, 1.0 FROM precalc_filter_bib_list INTERSECT SELECT id, 1.0 FROM precalc_bibs_by_copy_list) UNION (SELECT id, 1.0 FROM precalc_bib_filter_bib_list INTERSECT SELECT id, 1.0 FROM precalc_bibs_by_uri_list); END;
Function: rating.generic_fixed_rating_by_uri(value integer)
Returns: SET OF record
Language: PLPGSQL
BEGIN PERFORM rating.precalc_bibs_by_uri(badge_id); RETURN QUERY SELECT id, 1.0 FROM precalc_bib_filter_bib_list INTERSECT SELECT id, 1.0 FROM precalc_bibs_by_uri_list; END;
Function: rating.generic_fixed_rating_global(value integer)
Returns: SET OF record
Language: PLPGSQL
BEGIN RETURN QUERY SELECT id, 1.0 FROM precalc_bib_filter_bib_list; END;
Function: rating.holds_filled_over_time(value integer)
Returns: SET OF record
Language: PLPGSQL
DECLARE badge rating.badge_with_orgs%ROWTYPE; iage INT := 1; iint INT := NULL; iscale NUMERIC := NULL; BEGIN SELECT * INTO badge FROM rating.badge_with_orgs WHERE id = badge_id; IF badge.horizon_age IS NULL THEN RAISE EXCEPTION 'Badge "%" with id % requires a horizon age but has none.', badge.name, badge.id; END IF; PERFORM rating.precalc_bibs_by_copy(badge_id); SET LOCAL client_min_messages = error; DROP TABLE IF EXISTS precalc_bib_list; CREATE TEMP TABLE precalc_bib_list ON COMMIT DROP AS SELECT id FROM precalc_filter_bib_list INTERSECT SELECT id FROM precalc_bibs_by_copy_list; iint := EXTRACT(EPOCH FROM badge.importance_interval); IF badge.importance_age IS NOT NULL THEN iage := (EXTRACT(EPOCH FROM badge.importance_age) / iint)::INT; END IF; -- if iscale is smaller than 1, scaling slope will be shallow ... BEWARE! iscale := COALESCE(badge.importance_scale, 1.0); RETURN QUERY SELECT bib, SUM( holds * GREATEST( iscale * (iage - hage), 1.0 )) FROM ( SELECT f.id AS bib, (1 + EXTRACT(EPOCH FROM AGE(h.fulfillment_time)) / iint)::INT AS hage, COUNT(h.id)::INT AS holds FROM action.hold_request h JOIN reporter.hold_request_record rhrr ON (rhrr.id = h.id) JOIN precalc_bib_list f ON (f.id = rhrr.bib_record) WHERE h.fulfillment_time >= NOW() - badge.horizon_age AND h.request_lib = ANY (badge.orgs) GROUP BY 1, 2 ) x GROUP BY 1; END;
Function: rating.holds_holdable_ratio(value integer)
Returns: SET OF record
Language: PLPGSQL
DECLARE badge rating.badge_with_orgs%ROWTYPE; BEGIN SELECT * INTO badge FROM rating.badge_with_orgs WHERE id = badge_id; PERFORM rating.precalc_bibs_by_copy(badge_id); DELETE FROM precalc_copy_filter_bib_list WHERE id NOT IN ( SELECT id FROM precalc_filter_bib_list INTERSECT SELECT id FROM precalc_bibs_by_copy_list ); ANALYZE precalc_copy_filter_bib_list; RETURN QUERY SELECT cn.record AS bib, COUNT(DISTINCT m.hold)::NUMERIC / COUNT(DISTINCT cp.id)::NUMERIC FROM asset.copy cp JOIN precalc_copy_filter_bib_list c ON (cp.id = c.copy) JOIN asset.copy_location cl ON (cl.id = cp.location) JOIN config.copy_status cs ON (cs.id = cp.status) JOIN asset.call_number cn ON (cn.id = cp.call_number) JOIN action.hold_copy_map m ON (m.target_copy = cp.id) WHERE cn.owning_lib = ANY (badge.orgs) AND cp.holdable IS TRUE AND cl.holdable IS TRUE AND cs.holdable IS TRUE GROUP BY 1; END;
Function: rating.holds_placed_over_time(value integer)
Returns: SET OF record
Language: PLPGSQL
DECLARE badge rating.badge_with_orgs%ROWTYPE; iage INT := 1; iint INT := NULL; iscale NUMERIC := NULL; BEGIN SELECT * INTO badge FROM rating.badge_with_orgs WHERE id = badge_id; IF badge.horizon_age IS NULL THEN RAISE EXCEPTION 'Badge "%" with id % requires a horizon age but has none.', badge.name, badge.id; END IF; PERFORM rating.precalc_bibs_by_copy(badge_id); SET LOCAL client_min_messages = error; DROP TABLE IF EXISTS precalc_bib_list; CREATE TEMP TABLE precalc_bib_list ON COMMIT DROP AS SELECT id FROM precalc_filter_bib_list INTERSECT SELECT id FROM precalc_bibs_by_copy_list; iint := EXTRACT(EPOCH FROM badge.importance_interval); IF badge.importance_age IS NOT NULL THEN iage := (EXTRACT(EPOCH FROM badge.importance_age) / iint)::INT; END IF; -- if iscale is smaller than 1, scaling slope will be shallow ... BEWARE! iscale := COALESCE(badge.importance_scale, 1.0); RETURN QUERY SELECT bib, SUM( holds * GREATEST( iscale * (iage - hage), 1.0 )) FROM ( SELECT f.id AS bib, (1 + EXTRACT(EPOCH FROM AGE(h.request_time)) / iint)::INT AS hage, COUNT(h.id)::INT AS holds FROM action.hold_request h JOIN reporter.hold_request_record rhrr ON (rhrr.id = h.id) JOIN precalc_bib_list f ON (f.id = rhrr.bib_record) WHERE h.request_time >= NOW() - badge.horizon_age AND h.request_lib = ANY (badge.orgs) GROUP BY 1, 2 ) x GROUP BY 1; END;
Function: rating.holds_total_ratio(value integer)
Returns: SET OF record
Language: PLPGSQL
DECLARE badge rating.badge_with_orgs%ROWTYPE; BEGIN SELECT * INTO badge FROM rating.badge_with_orgs WHERE id = badge_id; PERFORM rating.precalc_bibs_by_copy(badge_id); DELETE FROM precalc_copy_filter_bib_list WHERE id NOT IN ( SELECT id FROM precalc_filter_bib_list INTERSECT SELECT id FROM precalc_bibs_by_copy_list ); ANALYZE precalc_copy_filter_bib_list; RETURN QUERY SELECT cn.record AS bib, COUNT(DISTINCT m.hold)::NUMERIC / COUNT(DISTINCT cp.id)::NUMERIC FROM asset.copy cp JOIN precalc_copy_filter_bib_list c ON (cp.id = c.copy) JOIN asset.call_number cn ON (cn.id = cp.call_number) JOIN action.hold_copy_map m ON (m.target_copy = cp.id) WHERE cn.owning_lib = ANY (badge.orgs) GROUP BY 1; END;
Function: rating.inhouse_over_time(value integer)
Returns: SET OF record
Language: PLPGSQL
DECLARE badge rating.badge_with_orgs%ROWTYPE; iage INT := 1; iint INT := NULL; iscale NUMERIC := NULL; BEGIN SELECT * INTO badge FROM rating.badge_with_orgs WHERE id = badge_id; IF badge.horizon_age IS NULL THEN RAISE EXCEPTION 'Badge "%" with id % requires a horizon age but has none.', badge.name, badge.id; END IF; PERFORM rating.precalc_bibs_by_copy(badge_id); DELETE FROM precalc_copy_filter_bib_list WHERE id NOT IN ( SELECT id FROM precalc_filter_bib_list INTERSECT SELECT id FROM precalc_bibs_by_copy_list ); ANALYZE precalc_copy_filter_bib_list; iint := EXTRACT(EPOCH FROM badge.importance_interval); IF badge.importance_age IS NOT NULL THEN iage := (EXTRACT(EPOCH FROM badge.importance_age) / iint)::INT; END IF; -- if iscale is smaller than 1, scaling slope will be shallow ... BEWARE! iscale := COALESCE(badge.importance_scale, 1.0); RETURN QUERY SELECT bib, SUM( uses * GREATEST( iscale * (iage - cage), 1.0 )) FROM ( SELECT cn.record AS bib, (1 + EXTRACT(EPOCH FROM AGE(u.use_time)) / iint)::INT AS cage, COUNT(u.id)::INT AS uses FROM action.in_house_use u JOIN precalc_copy_filter_bib_list cf ON (u.item = cf.copy) JOIN asset.copy cp ON (cp.id = u.item) JOIN asset.call_number cn ON (cn.id = cp.call_number) WHERE u.use_time >= NOW() - badge.horizon_age AND cn.owning_lib = ANY (badge.orgs) GROUP BY 1, 2 ) x GROUP BY 1; END;
Function: rating.org_unit_count(value integer)
Returns: SET OF record
Language: PLPGSQL
DECLARE badge rating.badge_with_orgs%ROWTYPE; BEGIN SELECT * INTO badge FROM rating.badge_with_orgs WHERE id = badge_id; PERFORM rating.precalc_bibs_by_copy(badge_id); DELETE FROM precalc_copy_filter_bib_list WHERE id NOT IN ( SELECT id FROM precalc_filter_bib_list INTERSECT SELECT id FROM precalc_bibs_by_copy_list ); ANALYZE precalc_copy_filter_bib_list; -- Use circ rather than owning lib here as that means "on the shelf at..." RETURN QUERY SELECT f.id::INT AS bib, COUNT(DISTINCT cp.circ_lib)::NUMERIC FROM asset.copy cp JOIN precalc_copy_filter_bib_list f ON (cp.id = f.copy) WHERE cp.circ_lib = ANY (badge.orgs) GROUP BY 1; END;
Function: rating.percent_time_circulating(value integer)
Returns: SET OF record
Language: PLPGSQL
DECLARE badge rating.badge_with_orgs%ROWTYPE; BEGIN SELECT * INTO badge FROM rating.badge_with_orgs WHERE id = badge_id; PERFORM rating.precalc_bibs_by_copy(badge_id); DELETE FROM precalc_copy_filter_bib_list WHERE id NOT IN ( SELECT id FROM precalc_filter_bib_list INTERSECT SELECT id FROM precalc_bibs_by_copy_list ); ANALYZE precalc_copy_filter_bib_list; RETURN QUERY SELECT bib, SUM(COALESCE(circ_time,0))::NUMERIC / SUM(age)::NUMERIC FROM (SELECT cn.record AS bib, cp.id, EXTRACT( EPOCH FROM AGE(cp.active_date) ) + 1 AS age, SUM( -- time copy spent circulating EXTRACT( EPOCH FROM AGE( COALESCE(circ.checkin_time, circ.stop_fines_time, NOW()), circ.xact_start ) ) )::NUMERIC AS circ_time FROM asset.copy cp JOIN precalc_copy_filter_bib_list c ON (cp.id = c.copy) JOIN asset.call_number cn ON (cn.id = cp.call_number) LEFT JOIN action.all_circulation_slim circ ON ( circ.target_copy = cp.id AND stop_fines NOT IN ( 'LOST', 'LONGOVERDUE', 'CLAIMSRETURNED', 'LONGOVERDUE' ) AND NOT ( checkin_time IS NULL AND stop_fines = 'MAXFINES' ) ) WHERE cn.owning_lib = ANY (badge.orgs) AND cp.active_date IS NOT NULL -- Next line requires that copies with no circs (circ.id IS NULL) also not be deleted AND ((circ.id IS NULL AND NOT cp.deleted) OR circ.id IS NOT NULL) GROUP BY 1,2,3 ) x GROUP BY 1; END;
Function: rating.precalc_attr_filter(attr_filter text)
Returns: integer
Language: PLPGSQL
DECLARE cnt INT := 0; afilter TEXT; BEGIN SET LOCAL client_min_messages = error; DROP TABLE IF EXISTS precalc_attr_filter_bib_list; IF attr_filter IS NOT NULL THEN afilter := metabib.compile_composite_attr(attr_filter); CREATE TEMP TABLE precalc_attr_filter_bib_list ON COMMIT DROP AS SELECT source AS id FROM metabib.record_attr_vector_list WHERE vlist @@ metabib.compile_composite_attr(attr_filter); ELSE CREATE TEMP TABLE precalc_attr_filter_bib_list ON COMMIT DROP AS SELECT source AS id FROM metabib.record_attr_vector_list; END IF; SELECT count(*) INTO cnt FROM precalc_attr_filter_bib_list; RETURN cnt; END;
Function: rating.precalc_bibs_by_copy(badge_id integer)
Returns: integer
Language: PLPGSQL
DECLARE cnt INT := 0; badge_row rating.badge_with_orgs%ROWTYPE; base TEXT; whr TEXT; BEGIN SELECT * INTO badge_row FROM rating.badge_with_orgs WHERE id = badge_id; SET LOCAL client_min_messages = error; DROP TABLE IF EXISTS precalc_bibs_by_copy_list; CREATE TEMP TABLE precalc_bibs_by_copy_list ON COMMIT DROP AS SELECT DISTINCT cn.record AS id FROM asset.call_number cn JOIN asset.copy cp ON (cp.call_number = cn.id AND NOT cp.deleted) JOIN precalc_copy_filter_bib_list f ON (cp.id = f.copy) WHERE cn.owning_lib = ANY (badge_row.orgs) AND NOT cn.deleted; SELECT count(*) INTO cnt FROM precalc_bibs_by_copy_list; RETURN cnt; END;
Function: rating.precalc_bibs_by_copy_or_uri(badge_id integer)
Returns: integer
Language: PLPGSQL
DECLARE cnt INT := 0; BEGIN PERFORM rating.precalc_bibs_by_copy(badge_id); PERFORM rating.precalc_bibs_by_uri(badge_id); SET LOCAL client_min_messages = error; DROP TABLE IF EXISTS precalc_bibs_by_copy_or_uri_list; CREATE TEMP TABLE precalc_bibs_by_copy_or_uri_list ON COMMIT DROP AS SELECT id FROM precalc_bibs_by_copy_list UNION SELECT id FROM precalc_bibs_by_uri_list; SELECT count(*) INTO cnt FROM precalc_bibs_by_copy_or_uri_list; RETURN cnt; END;
Function: rating.precalc_bibs_by_uri(badge_id integer)
Returns: integer
Language: PLPGSQL
DECLARE cnt INT := 0; badge_row rating.badge_with_orgs%ROWTYPE; BEGIN SELECT * INTO badge_row FROM rating.badge_with_orgs WHERE id = badge_id; SET LOCAL client_min_messages = error; DROP TABLE IF EXISTS precalc_bibs_by_uri_list; CREATE TEMP TABLE precalc_bibs_by_uri_list ON COMMIT DROP AS SELECT DISTINCT record AS id FROM asset.call_number cn JOIN asset.uri_call_number_map urim ON (urim.call_number = cn.id) JOIN asset.uri uri ON (urim.uri = uri.id AND uri.active) WHERE cn.owning_lib = ANY (badge_row.orgs) AND cn.label = '##URI##' AND NOT cn.deleted; SELECT count(*) INTO cnt FROM precalc_bibs_by_uri_list; RETURN cnt; END;
Function: rating.precalc_circ_mod_filter(cm text)
Returns: integer
Language: PLPGSQL
DECLARE cnt INT := 0; BEGIN SET LOCAL client_min_messages = error; DROP TABLE IF EXISTS precalc_circ_mod_filter_bib_list; IF cm IS NOT NULL THEN CREATE TEMP TABLE precalc_circ_mod_filter_bib_list ON COMMIT DROP AS SELECT cn.record AS id, cp.id AS copy FROM asset.call_number cn JOIN asset.copy cp ON (cn.id = cp.call_number) WHERE cp.circ_modifier = cm AND NOT cp.deleted; ELSE CREATE TEMP TABLE precalc_circ_mod_filter_bib_list ON COMMIT DROP AS SELECT cn.record AS id, cp.id AS copy FROM asset.call_number cn JOIN asset.copy cp ON (cn.id = cp.call_number) WHERE NOT cp.deleted; END IF; SELECT count(*) INTO cnt FROM precalc_circ_mod_filter_bib_list; RETURN cnt; END;
Function: rating.precalc_location_filter(loc integer)
Returns: integer
Language: PLPGSQL
DECLARE cnt INT := 0; BEGIN SET LOCAL client_min_messages = error; DROP TABLE IF EXISTS precalc_location_filter_bib_list; IF loc IS NOT NULL THEN CREATE TEMP TABLE precalc_location_filter_bib_list ON COMMIT DROP AS SELECT cn.record AS id, cp.id AS copy FROM asset.call_number cn JOIN asset.copy cp ON (cn.id = cp.call_number) JOIN asset.copy_location_group_map lg ON (cp.location = lg.location) WHERE lg.lgroup = loc AND NOT cp.deleted; ELSE CREATE TEMP TABLE precalc_location_filter_bib_list ON COMMIT DROP AS SELECT cn.record AS id, cp.id AS copy FROM asset.call_number cn JOIN asset.copy cp ON (cn.id = cp.call_number) WHERE NOT cp.deleted; END IF; SELECT count(*) INTO cnt FROM precalc_location_filter_bib_list; RETURN cnt; END;
Function: rating.precalc_src_filter(src integer)
Returns: integer
Language: PLPGSQL
DECLARE cnt INT := 0; BEGIN SET LOCAL client_min_messages = error; DROP TABLE IF EXISTS precalc_src_filter_bib_list; IF src IS NOT NULL THEN CREATE TEMP TABLE precalc_src_filter_bib_list ON COMMIT DROP AS SELECT id FROM biblio.record_entry WHERE source = src AND NOT deleted; ELSE CREATE TEMP TABLE precalc_src_filter_bib_list ON COMMIT DROP AS SELECT id FROM biblio.record_entry WHERE id > 0 AND NOT deleted; END IF; SELECT count(*) INTO cnt FROM precalc_src_filter_bib_list; RETURN cnt; END;
Function: rating.recalculate_badge_score(setup_only integer, badge_id boolean)
Returns: void
Language: PLPGSQL
DECLARE badge_row rating.badge%ROWTYPE; param rating.popularity_parameter%ROWTYPE; BEGIN SET LOCAL client_min_messages = error; -- Find what we're doing SELECT * INTO badge_row FROM rating.badge WHERE id = badge_id; SELECT * INTO param FROM rating.popularity_parameter WHERE id = badge_row.popularity_parameter; -- Calculate the filtered bib set, or all bibs if none PERFORM rating.precalc_attr_filter(badge_row.attr_filter); PERFORM rating.precalc_src_filter(badge_row.src_filter); PERFORM rating.precalc_circ_mod_filter(badge_row.circ_mod_filter); PERFORM rating.precalc_location_filter(badge_row.loc_grp_filter); -- Bring the bib-level filter lists together DROP TABLE IF EXISTS precalc_bib_filter_bib_list; CREATE TEMP TABLE precalc_bib_filter_bib_list ON COMMIT DROP AS SELECT id FROM precalc_attr_filter_bib_list INTERSECT SELECT id FROM precalc_src_filter_bib_list; -- Bring the copy-level filter lists together. We're keeping this for bib_by_copy filtering later. DROP TABLE IF EXISTS precalc_copy_filter_bib_list; CREATE TEMP TABLE precalc_copy_filter_bib_list ON COMMIT DROP AS SELECT id, copy FROM precalc_circ_mod_filter_bib_list INTERSECT SELECT id, copy FROM precalc_location_filter_bib_list; -- Bring the collapsed filter lists together DROP TABLE IF EXISTS precalc_filter_bib_list; CREATE TEMP TABLE precalc_filter_bib_list ON COMMIT DROP AS SELECT id FROM precalc_bib_filter_bib_list INTERSECT SELECT id FROM precalc_copy_filter_bib_list; CREATE INDEX precalc_filter_bib_list_idx ON precalc_filter_bib_list (id); IF setup_only THEN RETURN; END IF; -- If it's a fixed-rating badge, just do it ... IF badge_row.fixed_rating IS NOT NULL THEN DELETE FROM rating.record_badge_score WHERE badge = badge_id; EXECUTE $e$ INSERT INTO rating.record_badge_score (record, badge, score) SELECT record, $1, $2 FROM $e$ || param.func || $e$($1)$e$ USING badge_id, badge_row.fixed_rating; UPDATE rating.badge SET last_calc = NOW() WHERE id = badge_id; RETURN; END IF; -- else, calculate! -- Make a session-local scratchpad for calculating scores CREATE TEMP TABLE record_score_scratchpad ( bib BIGINT, value NUMERIC ) ON COMMIT DROP; -- Gather raw values EXECUTE $e$ INSERT INTO record_score_scratchpad (bib, value) SELECT * FROM $e$ || param.func || $e$($1)$e$ USING badge_id; IF badge_row.discard > 0 OR badge_row.percentile IS NOT NULL THEN -- To speed up discard-common CREATE INDEX record_score_scratchpad_score_idx ON record_score_scratchpad (value); ANALYZE record_score_scratchpad; END IF; IF badge_row.discard > 0 THEN -- Remove common low values (trim the long tail) DELETE FROM record_score_scratchpad WHERE value IN ( SELECT DISTINCT value FROM record_score_scratchpad ORDER BY value LIMIT badge_row.discard ); END IF; IF badge_row.percentile IS NOT NULL THEN -- Cut population down to exceptional records DELETE FROM record_score_scratchpad WHERE value <= ( SELECT value FROM ( SELECT value, CUME_DIST() OVER (ORDER BY value) AS p FROM record_score_scratchpad ) x WHERE p < badge_row.percentile / 100.0 ORDER BY p DESC LIMIT 1 ); END IF; -- And, finally, push new data in DELETE FROM rating.record_badge_score WHERE badge = badge_id; INSERT INTO rating.record_badge_score (badge, record, score) SELECT badge_id, bib, GREATEST(ROUND((CUME_DIST() OVER (ORDER BY value)) * 5), 1) AS value FROM record_score_scratchpad; DROP TABLE record_score_scratchpad; -- Now, finally-finally, mark the badge as recalculated UPDATE rating.badge SET last_calc = NOW() WHERE id = badge_id; RETURN; END;
Schema reporter
View: reporter.asset_call_number_dewey
F-Key | Name | Type | Description |
---|---|---|---|
call_number | bigint | ||
dewey | text | ||
dewey_block_tens | text | ||
dewey_block_hundreds | text | ||
dewey_range_tens | text | ||
dewey_range_hundreds | text |
SELECT call_number.id AS call_number , call_number_dewey (call_number.label) AS dewey , CASE WHEN (call_number_dewey (call_number.label) ~ '^[0-9]+\.?[0-9]*$'::text ) THEN btrim (to_char ( ( (10)::double precision * floor ( ( (call_number_dewey (call_number.label) )::double precision / (10)::double precision ) ) ) ,'000'::text ) ) ELSE NULL::text END AS dewey_block_tens , CASE WHEN (call_number_dewey (call_number.label) ~ '^[0-9]+\.?[0-9]*$'::text ) THEN btrim (to_char ( ( (100)::double precision * floor ( ( (call_number_dewey (call_number.label) )::double precision / (100)::double precision ) ) ) ,'000'::text ) ) ELSE NULL::text END AS dewey_block_hundreds , CASE WHEN (call_number_dewey (call_number.label) ~ '^[0-9]+\.?[0-9]*$'::text ) THEN ( (btrim (to_char ( ( (10)::double precision * floor ( ( (call_number_dewey (call_number.label) )::double precision / (10)::double precision ) ) ) ,'000'::text ) ) || '-'::text ) || btrim (to_char ( ( ( (10)::double precision * floor ( ( (call_number_dewey (call_number.label) )::double precision / (10)::double precision ) ) ) + (9)::double precision ) ,'000'::text ) ) ) ELSE NULL::text END AS dewey_range_tens , CASE WHEN (call_number_dewey (call_number.label) ~ '^[0-9]+\.?[0-9]*$'::text ) THEN ( (btrim (to_char ( ( (100)::double precision * floor ( ( (call_number_dewey (call_number.label) )::double precision / (100)::double precision ) ) ) ,'000'::text ) ) || '-'::text ) || btrim (to_char ( ( ( (100)::double precision * floor ( ( (call_number_dewey (call_number.label) )::double precision / (100)::double precision ) ) ) + (99)::double precision ) ,'000'::text ) ) ) ELSE NULL::text END AS dewey_range_hundreds FROM asset.call_number WHERE (call_number_dewey (call_number.label) ~ '^[0-9]'::text );
View: reporter.circ_type
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
type | text |
SELECT circulation.id , CASE WHEN (circulation.opac_renewal OR circulation.phone_renewal OR circulation.desk_renewal OR circulation.auto_renewal ) THEN 'RENEWAL'::text ELSE 'CHECKOUT'::text END AS type FROM action.circulation;
View: reporter.completed_reports
F-Key | Name | Type | Description |
---|---|---|---|
run | integer | ||
report | integer | ||
template | integer | ||
template_owner | integer | ||
report_owner | integer | ||
runner | integer | ||
template_folder | integer | ||
report_folder | integer | ||
output_folder | integer | ||
report_name | text | ||
template_name | text | ||
start_time | timestamp with time zone | ||
run_time | timestamp with time zone | ||
complete_time | timestamp with time zone | ||
error_code | integer | ||
error_text | text |
SELECT s.id AS run , r.id AS report , t.id AS template , t.owner AS template_owner , r.owner AS report_owner , s.runner , t.folder AS template_folder , r.folder AS report_folder , s.folder AS output_folder , r.name AS report_name , t.name AS template_name , s.start_time , s.run_time , s.complete_time , s.error_code , s.error_text FROM ( (reporter.schedule s JOIN reporter.report r ON ( (r.id = s.report) ) ) JOIN reporter.template t ON ( (t.id = r.template) ) ) WHERE (s.complete_time IS NOT NULL);
View: reporter.currently_running
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
runner_barcode | text | ||
name | text | ||
run_time | timestamp with time zone | ||
scheduled_wait_time | interval |
SELECT s.id , c.barcode AS runner_barcode , r.name , s.run_time , (s.run_time - now () ) AS scheduled_wait_time FROM ( ( (reporter.schedule s JOIN reporter.report r ON ( (r.id = s.report) ) ) JOIN actor.usr u ON ( (s.runner = u.id) ) ) JOIN actor.card c ON ( (c.id = u.card) ) ) WHERE ( (s.start_time IS NOT NULL) AND (s.complete_time IS NULL) );
View: reporter.demographic
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
dob | date | ||
general_division | text | ||
age_division | text |
SELECT u.id , u.dob , CASE WHEN (u.dob IS NULL) THEN 'Adult'::text WHEN (age ( (u.dob)::timestamp with time zone ) > '18 years'::interval ) THEN 'Adult'::text ELSE 'Juvenile'::text END AS general_division , CASE WHEN (u.dob IS NULL) THEN 'No Date of Birth Entered'::text WHEN ( (age ( (u.dob)::timestamp with time zone ) >= '00:00:00'::interval ) AND (age ( (u.dob)::timestamp with time zone ) < '6 years'::interval ) ) THEN 'Child 0-5 Years Old'::text WHEN ( (age ( (u.dob)::timestamp with time zone ) >= '6 years'::interval ) AND (age ( (u.dob)::timestamp with time zone ) < '13 years'::interval ) ) THEN 'Child 6-12 Years Old'::text WHEN ( (age ( (u.dob)::timestamp with time zone ) >= '13 years'::interval ) AND (age ( (u.dob)::timestamp with time zone ) < '18 years'::interval ) ) THEN 'Teen 13-17 Years Old'::text WHEN ( (age ( (u.dob)::timestamp with time zone ) >= '18 years'::interval ) AND (age ( (u.dob)::timestamp with time zone ) < '26 years'::interval ) ) THEN 'Adult 18-25 Years Old'::text WHEN ( (age ( (u.dob)::timestamp with time zone ) >= '26 years'::interval ) AND (age ( (u.dob)::timestamp with time zone ) < '50 years'::interval ) ) THEN 'Adult 26-49 Years Old'::text WHEN ( (age ( (u.dob)::timestamp with time zone ) >= '50 years'::interval ) AND (age ( (u.dob)::timestamp with time zone ) < '60 years'::interval ) ) THEN 'Adult 50-59 Years Old'::text WHEN ( (age ( (u.dob)::timestamp with time zone ) >= '60 years'::interval ) AND (age ( (u.dob)::timestamp with time zone ) < '70 years'::interval ) ) THEN 'Adult 60-69 Years Old'::text WHEN (age ( (u.dob)::timestamp with time zone ) >= '70 years'::interval ) THEN 'Adult 70+'::text ELSE NULL::text END AS age_division FROM actor.usr u;
Table: reporter.hold_request_record
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | PRIMARY KEY | |
target | bigint | ||
hold_type | text | ||
bib_record | bigint |
Table: reporter.materialized_simple_record
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY | |
fingerprint | text | ||
quality | integer | ||
tcn_source | text | ||
tcn_value | text | ||
title | text | ||
author | text | ||
publisher | text | ||
pubdate | text | ||
isbn | text[] | ||
issn | text[] |
View: reporter.old_super_simple_record
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
fingerprint | text | ||
quality | integer | ||
tcn_source | text | ||
tcn_value | text | ||
title | text | ||
author | text | ||
publisher | text | ||
pubdate | text | ||
isbn | text[] | ||
issn | text[] |
SELECT r.id , r.fingerprint , r.quality , r.tcn_source , r.tcn_value , oils_json_to_text (d.title) AS title , oils_json_to_text (d.author) AS author , oils_json_to_text (d.publisher) AS publisher , oils_json_to_text (d.pubdate) AS pubdate , CASE WHEN (d.isbn = 'null'::text) THEN NULL::text[] ELSE ( SELECT ARRAY ( SELECT json_array_elements_text ( (d.isbn)::json ) AS json_array_elements_text ) AS "array" ) END AS isbn , CASE WHEN (d.issn = 'null'::text) THEN NULL::text[] ELSE ( SELECT ARRAY ( SELECT json_array_elements_text ( (d.issn)::json ) AS json_array_elements_text ) AS "array" ) END AS issn FROM (biblio.record_entry r JOIN metabib.wide_display_entry d ON ( (r.id = d.source) ) );
Table: reporter.output_folder
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
reporter.output_folder.id | parent | integer | |
actor.usr.id | owner | integer | NOT NULL |
create_time | timestamp with time zone | NOT NULL DEFAULT now() | |
name | text | NOT NULL | |
shared | boolean | NOT NULL DEFAULT false | |
simple_reporter | boolean | NOT NULL DEFAULT false | |
actor.org_unit.id | share_with | integer |
Tables referencing this one via Foreign Key Constraints:
rpt_output_fldr_owner_idx ownerView: reporter.overdue_circs
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
usr | integer | ||
xact_start | timestamp with time zone | ||
xact_finish | timestamp with time zone | ||
unrecovered | boolean | ||
target_copy | bigint | ||
circ_lib | integer | ||
circ_staff | integer | ||
checkin_staff | integer | ||
checkin_lib | integer | ||
renewal_remaining | integer | ||
grace_period | interval | ||
due_date | timestamp with time zone | ||
stop_fines_time | timestamp with time zone | ||
checkin_time | timestamp with time zone | ||
create_time | timestamp with time zone | ||
duration | interval | ||
fine_interval | interval | ||
recurring_fine | numeric(6,2) | ||
max_fine | numeric(6,2) | ||
phone_renewal | boolean | ||
desk_renewal | boolean | ||
opac_renewal | boolean | ||
duration_rule | text | ||
recurring_fine_rule | text | ||
max_fine_rule | text | ||
stop_fines | text | ||
workstation | integer | ||
checkin_workstation | integer | ||
copy_location | integer | ||
checkin_scan_time | timestamp with time zone | ||
auto_renewal | boolean | ||
auto_renewal_remaining | integer | ||
parent_circ | bigint |
SELECT circulation.id , circulation.usr , circulation.xact_start , circulation.xact_finish , circulation.unrecovered , circulation.target_copy , circulation.circ_lib , circulation.circ_staff , circulation.checkin_staff , circulation.checkin_lib , circulation.renewal_remaining , circulation.grace_period , circulation.due_date , circulation.stop_fines_time , circulation.checkin_time , circulation.create_time , circulation.duration , circulation.fine_interval , circulation.recurring_fine , circulation.max_fine , circulation.phone_renewal , circulation.desk_renewal , circulation.opac_renewal , circulation.duration_rule , circulation.recurring_fine_rule , circulation.max_fine_rule , circulation.stop_fines , circulation.workstation , circulation.checkin_workstation , circulation.copy_location , circulation.checkin_scan_time , circulation.auto_renewal , circulation.auto_renewal_remaining , circulation.parent_circ FROM action.circulation WHERE ( (circulation.checkin_time IS NULL) AND ( (circulation.stop_fines <> ALL (ARRAY['LOST'::text ,'CLAIMSRETURNED'::text] ) ) OR (circulation.stop_fines IS NULL) ) AND (circulation.due_date < now () ) );
View: reporter.overdue_reports
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
runner_barcode | text | ||
name | text | ||
run_time | timestamp with time zone | ||
scheduled_wait_time | interval |
SELECT s.id , c.barcode AS runner_barcode , r.name , s.run_time , (s.run_time - now () ) AS scheduled_wait_time FROM ( ( (reporter.schedule s JOIN reporter.report r ON ( (r.id = s.report) ) ) JOIN actor.usr u ON ( (s.runner = u.id) ) ) JOIN actor.card c ON ( (c.id = u.card) ) ) WHERE ( (s.start_time IS NULL) AND (s.run_time < now () ) );
View: reporter.pending_reports
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
runner_barcode | text | ||
name | text | ||
run_time | timestamp with time zone | ||
scheduled_wait_time | interval |
SELECT s.id , c.barcode AS runner_barcode , r.name , s.run_time , (s.run_time - now () ) AS scheduled_wait_time FROM ( ( (reporter.schedule s JOIN reporter.report r ON ( (r.id = s.report) ) ) JOIN actor.usr u ON ( (s.runner = u.id) ) ) JOIN actor.card c ON ( (c.id = u.card) ) ) WHERE (s.start_time IS NULL);
Table: reporter.report
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.usr.id | owner | integer | NOT NULL |
create_time | timestamp with time zone | NOT NULL DEFAULT now() | |
name | text | NOT NULL DEFAULT ''::text | |
description | text | NOT NULL DEFAULT ''::text | |
reporter.template.id | template | integer | NOT NULL |
data | text | NOT NULL | |
reporter.report_folder.id | folder | integer | NOT NULL |
recur | boolean | NOT NULL DEFAULT false | |
recurrence | interval |
Tables referencing this one via Foreign Key Constraints:
rpt_rpt_fldr_idx folder rpt_rpt_owner_idx ownerTable: reporter.report_folder
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
reporter.report_folder.id | parent | integer | |
actor.usr.id | owner | integer | NOT NULL |
create_time | timestamp with time zone | NOT NULL DEFAULT now() | |
name | text | NOT NULL | |
shared | boolean | NOT NULL DEFAULT false | |
simple_reporter | boolean | NOT NULL DEFAULT false | |
actor.org_unit.id | share_with | integer |
Tables referencing this one via Foreign Key Constraints:
rpt_rpt_fldr_owner_idx ownerTable: reporter.schedule
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
reporter.report.id | report | integer | NOT NULL |
reporter.output_folder.id | folder | integer | NOT NULL |
actor.usr.id | runner | integer | NOT NULL |
run_time | timestamp with time zone | NOT NULL DEFAULT now() | |
start_time | timestamp with time zone | ||
complete_time | timestamp with time zone | ||
text | |||
excel_format | boolean | NOT NULL DEFAULT true | |
html_format | boolean | NOT NULL DEFAULT true | |
csv_format | boolean | NOT NULL DEFAULT true | |
chart_pie | boolean | NOT NULL DEFAULT false | |
chart_bar | boolean | NOT NULL DEFAULT false | |
chart_line | boolean | NOT NULL DEFAULT false | |
error_code | integer | ||
error_text | text |
View: reporter.simple_record
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
metarecord | bigint | ||
fingerprint | text | ||
quality | integer | ||
tcn_source | text | ||
tcn_value | text | ||
title | text | ||
uniform_title | text | ||
author | text | ||
publisher | text | ||
pubdate | text | ||
series_title | text | ||
series_statement | text | ||
summary | text | ||
isbn | text[] | ||
issn | text[] | ||
topic_subject | text[] | ||
geographic_subject | text[] | ||
genre | text[] | ||
name_subject | text[] | ||
corporate_subject | text[] | ||
external_uri | text[] |
SELECT r.id , s.metarecord , r.fingerprint , r.quality , r.tcn_source , r.tcn_value , title.value AS title , uniform_title.value AS uniform_title , author.value AS author , publisher.value AS publisher , "substring" (pubdate.value ,'\d+'::text ) AS pubdate , series_title.value AS series_title , series_statement.value AS series_statement , summary.value AS summary , array_agg (DISTINCT replace ("substring" (isbn.value ,'^\S+'::text ) ,'-'::text ,''::text ) ) AS isbn , array_agg (DISTINCT regexp_replace (issn.value ,'^\S*(\d{4})[-\s](\d{3,4}x?)'::text ,'\1 \2'::text ) ) AS issn , ARRAY ( SELECT DISTINCT full_rec.value FROM metabib.full_rec WHERE ( (full_rec.tag = '650'::bpchar) AND (full_rec.subfield = 'a'::text) AND (full_rec.record = r.id) ) ) AS topic_subject , ARRAY ( SELECT DISTINCT full_rec.value FROM metabib.full_rec WHERE ( (full_rec.tag = '651'::bpchar) AND (full_rec.subfield = 'a'::text) AND (full_rec.record = r.id) ) ) AS geographic_subject , ARRAY ( SELECT DISTINCT full_rec.value FROM metabib.full_rec WHERE ( (full_rec.tag = '655'::bpchar) AND (full_rec.subfield = 'a'::text) AND (full_rec.record = r.id) ) ) AS genre , ARRAY ( SELECT DISTINCT full_rec.value FROM metabib.full_rec WHERE ( (full_rec.tag = '600'::bpchar) AND (full_rec.subfield = 'a'::text) AND (full_rec.record = r.id) ) ) AS name_subject , ARRAY ( SELECT DISTINCT full_rec.value FROM metabib.full_rec WHERE ( (full_rec.tag = '610'::bpchar) AND (full_rec.subfield = 'a'::text) AND (full_rec.record = r.id) ) ) AS corporate_subject , ARRAY ( SELECT full_rec.value FROM metabib.full_rec WHERE ( (full_rec.tag = '856'::bpchar) AND (full_rec.subfield = ANY (ARRAY['3'::text ,'y'::text ,'u'::text] ) ) AND (full_rec.record = r.id) ) ORDER BY CASE WHEN (full_rec.subfield = ANY (ARRAY['3'::text ,'y'::text] ) ) THEN 0 ELSE 1 END ) AS external_uri FROM ( ( ( ( ( ( ( ( ( ( (biblio.record_entry r JOIN metabib.metarecord_source_map s ON ( (s.source = r.id) ) ) LEFT JOIN metabib.full_rec uniform_title ON ( ( (r.id = uniform_title.record) AND (uniform_title.tag = '240'::bpchar) AND (uniform_title.subfield = 'a'::text) ) ) ) LEFT JOIN metabib.full_rec title ON ( ( (r.id = title.record) AND (title.tag = '245'::bpchar) AND (title.subfield = 'a'::text) ) ) ) LEFT JOIN metabib.full_rec author ON ( ( (r.id = author.record) AND (author.tag = '100'::bpchar) AND (author.subfield = 'a'::text) ) ) ) LEFT JOIN metabib.full_rec publisher ON ( ( (r.id = publisher.record) AND ( (publisher.tag = '260'::bpchar) OR ( (publisher.tag = '264'::bpchar) AND (publisher.ind2 = '1'::text) ) ) AND (publisher.subfield = 'b'::text) ) ) ) LEFT JOIN metabib.full_rec pubdate ON ( ( (r.id = pubdate.record) AND ( (pubdate.tag = '260'::bpchar) OR ( (pubdate.tag = '264'::bpchar) AND (pubdate.ind2 = '1'::text) ) ) AND (pubdate.subfield = 'c'::text) ) ) ) LEFT JOIN metabib.full_rec isbn ON ( ( (r.id = isbn.record) AND (isbn.tag = ANY (ARRAY['024'::bpchar ,'020'::bpchar] ) ) AND (isbn.subfield = ANY (ARRAY['a'::text ,'z'::text] ) ) ) ) ) LEFT JOIN metabib.full_rec issn ON ( ( (r.id = issn.record) AND (issn.tag = '022'::bpchar) AND (issn.subfield = 'a'::text) ) ) ) LEFT JOIN metabib.full_rec series_title ON ( ( (r.id = series_title.record) AND (series_title.tag = ANY (ARRAY['830'::bpchar ,'440'::bpchar] ) ) AND (series_title.subfield = 'a'::text) ) ) ) LEFT JOIN metabib.full_rec series_statement ON ( ( (r.id = series_statement.record) AND (series_statement.tag = '490'::bpchar) AND (series_statement.subfield = 'a'::text) ) ) ) LEFT JOIN metabib.full_rec summary ON ( ( (r.id = summary.record) AND (summary.tag = '520'::bpchar) AND (summary.subfield = 'a'::text) ) ) ) GROUP BY r.id , s.metarecord , r.fingerprint , r.quality , r.tcn_source , r.tcn_value , title.value , uniform_title.value , author.value , publisher.value , ("substring" (pubdate.value ,'\d+'::text ) ) , series_title.value , series_statement.value , summary.value;
View: reporter.super_simple_record
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | ||
fingerprint | text | ||
quality | integer | ||
tcn_source | text | ||
tcn_value | text | ||
title | text | ||
author | text | ||
publisher | text | ||
pubdate | text | ||
isbn | text[] | ||
issn | text[] |
SELECT materialized_simple_record.id , materialized_simple_record.fingerprint , materialized_simple_record.quality , materialized_simple_record.tcn_source , materialized_simple_record.tcn_value , materialized_simple_record.title , materialized_simple_record.author , materialized_simple_record.publisher , materialized_simple_record.pubdate , materialized_simple_record.isbn , materialized_simple_record.issn FROM reporter.materialized_simple_record;
Table: reporter.template
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.usr.id | owner | integer | NOT NULL |
create_time | timestamp with time zone | NOT NULL DEFAULT now() | |
name | text | NOT NULL | |
description | text | NOT NULL DEFAULT ''::text | |
data | text | NOT NULL | |
reporter.template_folder.id | folder | integer | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
rpt_tmpl_fldr_idx folder rpt_tmpl_owner_idx ownerTable: reporter.template_folder
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
reporter.template_folder.id | parent | integer | |
actor.usr.id | owner | integer | NOT NULL |
create_time | timestamp with time zone | NOT NULL DEFAULT now() | |
name | text | NOT NULL | |
shared | boolean | NOT NULL DEFAULT false | |
simple_reporter | boolean | NOT NULL DEFAULT false | |
actor.org_unit.id | share_with | integer |
Tables referencing this one via Foreign Key Constraints:
rpt_tmpl_fldr_owner_idx ownerView: reporter.xact_billing_totals
F-Key | Name | Type | Description |
---|---|---|---|
xact | bigint | ||
unvoided | numeric | ||
voided | numeric | ||
total | numeric |
SELECT b.xact , sum ( CASE WHEN b.voided THEN (0)::numeric ELSE b.amount END ) AS unvoided , sum ( CASE WHEN b.voided THEN b.amount ELSE (0)::numeric END ) AS voided , sum (b.amount) AS total FROM money.billing b GROUP BY b.xact;
View: reporter.xact_paid_totals
F-Key | Name | Type | Description |
---|---|---|---|
xact | bigint | ||
unvoided | numeric | ||
voided | numeric | ||
total | numeric |
SELECT b.xact , sum ( CASE WHEN b.voided THEN (0)::numeric ELSE b.amount END ) AS unvoided , sum ( CASE WHEN b.voided THEN b.amount ELSE (0)::numeric END ) AS voided , sum (b.amount) AS total FROM money.payment b GROUP BY b.xact;
Function: reporter.disable_materialized_simple_record_trigger()
Returns: void
Language: SQL
DROP TRIGGER IF EXISTS bbb_simple_rec_trigger ON biblio.record_entry;
Function: reporter.enable_materialized_simple_record_trigger()
Returns: void
Language: SQL
TRUNCATE TABLE reporter.materialized_simple_record; INSERT INTO reporter.materialized_simple_record (id,fingerprint,quality,tcn_source,tcn_value,title,author,publisher,pubdate,isbn,issn) SELECT DISTINCT ON (id) * FROM reporter.old_super_simple_record; CREATE TRIGGER bbb_simple_rec_trigger AFTER INSERT OR UPDATE OR DELETE ON biblio.record_entry FOR EACH ROW EXECUTE PROCEDURE reporter.simple_rec_trigger();
Function: reporter.hold_request_record_mapper()
Returns: trigger
Language: PLPGSQL
BEGIN IF TG_OP = 'INSERT' THEN INSERT INTO reporter.hold_request_record (id, target, hold_type, bib_record) SELECT NEW.id, NEW.target, NEW.hold_type, CASE WHEN NEW.hold_type = 'T' THEN NEW.target WHEN NEW.hold_type = 'I' THEN (SELECT ssub.record_entry FROM serial.subscription ssub JOIN serial.issuance si ON (si.subscription = ssub.id) WHERE si.id = NEW.target) WHEN NEW.hold_type = 'V' THEN (SELECT cn.record FROM asset.call_number cn WHERE cn.id = NEW.target) WHEN NEW.hold_type IN ('C','R','F') THEN (SELECT cn.record FROM asset.call_number cn JOIN asset.copy cp ON (cn.id = cp.call_number) WHERE cp.id = NEW.target) WHEN NEW.hold_type = 'M' THEN (SELECT mr.master_record FROM metabib.metarecord mr WHERE mr.id = NEW.target) WHEN NEW.hold_type = 'P' THEN (SELECT bmp.record FROM biblio.monograph_part bmp WHERE bmp.id = NEW.target) END AS bib_record; ELSIF TG_OP = 'UPDATE' AND (OLD.target <> NEW.target OR OLD.hold_type <> NEW.hold_type) THEN UPDATE reporter.hold_request_record SET target = NEW.target, hold_type = NEW.hold_type, bib_record = CASE WHEN NEW.hold_type = 'T' THEN NEW.target WHEN NEW.hold_type = 'I' THEN (SELECT ssub.record_entry FROM serial.subscription ssub JOIN serial.issuance si ON (si.subscription = ssub.id) WHERE si.id = NEW.target) WHEN NEW.hold_type = 'V' THEN (SELECT cn.record FROM asset.call_number cn WHERE cn.id = NEW.target) WHEN NEW.hold_type IN ('C','R','F') THEN (SELECT cn.record FROM asset.call_number cn JOIN asset.copy cp ON (cn.id = cp.call_number) WHERE cp.id = NEW.target) WHEN NEW.hold_type = 'M' THEN (SELECT mr.master_record FROM metabib.metarecord mr WHERE mr.id = NEW.target) WHEN NEW.hold_type = 'P' THEN (SELECT bmp.record FROM biblio.monograph_part bmp WHERE bmp.id = NEW.target) END WHERE id = NEW.id; END IF; RETURN NEW; END;
Function: reporter.intersect_user_perm_ou(perm_code bigint, staff_id bigint, context_ou text)
Returns: boolean
Language: SQL
SELECT CASE WHEN context_ou IN (SELECT * FROM permission.usr_has_perm_at_all(staff_id::INT, perm_code)) THEN TRUE ELSE FALSE END;
Function: reporter.refresh_materialized_simple_record()
Returns: void
Language: SQL
SELECT reporter.disable_materialized_simple_record_trigger(); SELECT reporter.enable_materialized_simple_record_trigger();
Function: reporter.simple_rec_delete(r_id bigint)
Returns: boolean
Language: SQL
SELECT reporter.simple_rec_update($1, TRUE);
Function: reporter.simple_rec_trigger()
Returns: trigger
Language: PLPGSQL
BEGIN IF TG_OP = 'DELETE' THEN PERFORM reporter.simple_rec_delete(NEW.id); ELSE PERFORM reporter.simple_rec_update(NEW.id); END IF; RETURN NEW; END;
Function: reporter.simple_rec_update(deleted bigint, r_id boolean)
Returns: boolean
Language: PLPGSQL
BEGIN DELETE FROM reporter.materialized_simple_record WHERE id = r_id; IF NOT deleted THEN INSERT INTO reporter.materialized_simple_record SELECT DISTINCT ON (id) * FROM reporter.old_super_simple_record WHERE id = r_id; END IF; RETURN TRUE; END;
Function: reporter.simple_rec_update(r_id bigint)
Returns: boolean
Language: SQL
SELECT reporter.simple_rec_update($1, FALSE);
Schema search
View: search.best_tsconfig
F-Key | Name | Type | Description |
---|---|---|---|
id | integer | ||
ts_config | text |
SELECT m.id , COALESCE (f.ts_config , c.ts_config ,'simple'::text ) AS ts_config FROM ( (config.metabib_field m LEFT JOIN config.metabib_class_ts_map c ON ( ( (c.field_class = m.field_class) AND (c.index_weight = 'C'::bpchar) ) ) ) LEFT JOIN config.metabib_field_ts_map f ON ( ( (f.metabib_field = m.id) AND (f.index_weight = 'C'::bpchar) ) ) );
Table: search.relevance_adjustment
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
active | boolean | NOT NULL DEFAULT true | |
config.metabib_field.id | field | integer | NOT NULL |
bump_type | text | NOT NULL | |
multiplier | numeric | NOT NULL DEFAULT 1.0 |
Name | Constraint |
---|---|
relevance_adjustment_bump_type_check | CHECK ((bump_type = ANY (ARRAY['word_order'::text, 'first_word'::text, 'full_match'::text]))) |
Table: search.symspell_dictionary
F-Key | Name | Type | Description |
---|---|---|---|
keyword_count | integer | NOT NULL | |
title_count | integer | NOT NULL | |
author_count | integer | NOT NULL | |
subject_count | integer | NOT NULL | |
series_count | integer | NOT NULL | |
identifier_count | integer | NOT NULL | |
prefix_key | text | PRIMARY KEY | |
keyword_suggestions | text[] | ||
title_suggestions | text[] | ||
author_suggestions | text[] | ||
subject_suggestions | text[] | ||
series_suggestions | text[] | ||
identifier_suggestions | text[] |
Table: search.symspell_dictionary_updates
F-Key | Name | Type | Description |
---|---|---|---|
transaction_id | bigint | ||
keyword_count | integer | NOT NULL | |
title_count | integer | NOT NULL | |
author_count | integer | NOT NULL | |
subject_count | integer | NOT NULL | |
series_count | integer | NOT NULL | |
identifier_count | integer | NOT NULL | |
prefix_key | text | NOT NULL | |
keyword_suggestions | text[] | ||
title_suggestions | text[] | ||
author_suggestions | text[] | ||
subject_suggestions | text[] | ||
series_suggestions | text[] | ||
identifier_suggestions | text[] |
Function: search.calculate_visibility_attribute(attr integer, value text)
Returns: integer
Language: SQL
SELECT ((CASE $2 WHEN 'luri_org' THEN 0 -- "b" attr WHEN 'bib_source' THEN 1 -- "b" attr WHEN 'copy_flags' THEN 0 -- "c" attr WHEN 'owning_lib' THEN 1 -- "c" attr WHEN 'circ_lib' THEN 2 -- "c" attr WHEN 'status' THEN 3 -- "c" attr WHEN 'location' THEN 4 -- "c" attr WHEN 'location_group' THEN 5 -- "c" attr END) << 28 ) | $1; /* copy_flags bit positions, LSB-first: 0: asset.copy.opac_visible When adding flags, you must update asset.all_visible_flags() Because bib and copy values are stored separately, we can reuse shifts, saving us some space. We could probably take back a bit too, but I'm not sure its worth squeezing that last one out. We'd be left with just 2 slots for copy attrs, rather than 10. */
Function: search.calculate_visibility_attribute_list(value text, attr integer[])
Returns: integer[]
Language: SQL
SELECT ARRAY_AGG(search.calculate_visibility_attribute(x, $1)) FROM UNNEST($2) AS X;
Function: search.calculate_visibility_attribute_test(negate text, value integer[], attr boolean)
Returns: text
Language: SQL
SELECT CASE WHEN $3 THEN '!' ELSE '' END || '(' || ARRAY_TO_STRING(search.calculate_visibility_attribute_list($1,$2),'|') || ')';
Function: search.disable_symspell_reification()
Returns: void
Language: SQL
INSERT INTO config.internal_flag (name,enabled) VALUES ('ingest.disable_symspell_reification',TRUE) ON CONFLICT (name) DO UPDATE SET enabled = TRUE;
Function: search.enable_symspell_reification()
Returns: void
Language: SQL
UPDATE config.internal_flag SET enabled = FALSE WHERE name = 'ingest.disable_symspell_reification';
Function: search.facets_for_metarecord_set(count text[], value bigint[])
Returns: SET OF record
Language: SQL
SELECT id, value, count FROM ( SELECT mfae.field AS id, mfae.value, COUNT(DISTINCT mmrsm.metarecord), row_number() OVER ( PARTITION BY mfae.field ORDER BY COUNT(distinct mmrsm.metarecord) DESC ) AS rownum FROM metabib.facet_entry mfae JOIN metabib.metarecord_source_map mmrsm ON (mfae.source = mmrsm.source) JOIN config.metabib_field cmf ON (cmf.id = mfae.field) WHERE mmrsm.metarecord IN (SELECT * FROM unnest($2)) AND cmf.facet_field AND cmf.field_class NOT IN (SELECT * FROM unnest($1)) GROUP by 1, 2 ) all_facets WHERE rownum <= (SELECT COALESCE((SELECT value::INT FROM config.global_flag WHERE name = 'search.max_facets_per_field' AND enabled), 1000));
Function: search.facets_for_record_set(count text[], value bigint[])
Returns: SET OF record
Language: SQL
SELECT id, value, count FROM ( SELECT mfae.field AS id, mfae.value, COUNT(DISTINCT mfae.source), row_number() OVER ( PARTITION BY mfae.field ORDER BY COUNT(DISTINCT mfae.source) DESC ) AS rownum FROM metabib.facet_entry mfae JOIN config.metabib_field cmf ON (cmf.id = mfae.field) WHERE mfae.source = ANY ($2) AND cmf.facet_field AND cmf.field_class NOT IN (SELECT * FROM unnest($1)) GROUP by 1, 2 ) all_facets WHERE rownum <= ( SELECT COALESCE( (SELECT value::INT FROM config.global_flag WHERE name = 'search.max_facets_per_field' AND enabled), 1000 ) );
Function: search.highlight_display_fields(delimiter bigint, maxfrags text, shortwords text, maxwords boolean, minwords integer, hl_all integer, css_class integer, tsq_map integer, rid text)
Returns: SET OF highlight_result
Language: PLPGSQL
DECLARE tsq_hstore TEXT; tsq TEXT; fields TEXT; afields INT[]; seen INT[]; BEGIN IF (tsq_map ILIKE 'hstore%') THEN EXECUTE 'SELECT ' || tsq_map INTO tsq_hstore; ELSE tsq_hstore := tsq_map::HSTORE; END IF; FOR tsq, fields IN SELECT key, value FROM each(tsq_hstore::HSTORE) LOOP SELECT ARRAY_AGG(unnest::INT) INTO afields FROM unnest(regexp_split_to_array(fields,',')); seen := seen || afields; RETURN QUERY SELECT * FROM search.highlight_display_fields_impl( rid, tsq, afields, css_class, hl_all,minwords, maxwords, shortwords, maxfrags, delimiter ); END LOOP; RETURN QUERY SELECT id, source, field, evergreen.escape_for_html(value) AS value, evergreen.escape_for_html(value) AS highlight FROM metabib.display_entry WHERE source = rid AND NOT (field = ANY (seen)); END;
Function: search.highlight_display_fields_impl(delimiter bigint, maxfrags text, shortwords integer[], maxwords text, minwords boolean, hl_all integer, css_class integer, field_list integer, tsq integer, rid text)
Returns: SET OF highlight_result
Language: PLPGSQL
DECLARE opts TEXT := ''; v_css_class TEXT := css_class; v_delimiter TEXT := delimiter; v_field_list INT[] := field_list; hl_query TEXT; BEGIN IF v_delimiter LIKE $$%'%$$ OR v_delimiter LIKE '%"%' THEN --" v_delimiter := ' ... '; END IF; IF NOT hl_all THEN opts := opts || 'MinWords=' || minwords; opts := opts || ', MaxWords=' || maxwords; opts := opts || ', ShortWords=' || shortwords; opts := opts || ', MaxFragments=' || maxfrags; opts := opts || ', FragmentDelimiter="' || delimiter || '"'; ELSE opts := opts || 'HighlightAll=TRUE'; END IF; IF v_css_class LIKE $$%'%$$ OR v_css_class LIKE '%"%' THEN -- " v_css_class := 'oils_SH'; END IF; opts := opts || $$, StopSel=</b>, StartSel="<b class='$$ || v_css_class; -- " IF v_field_list = '{}'::INT[] THEN SELECT ARRAY_AGG(id) INTO v_field_list FROM config.metabib_field WHERE display_field; END IF; hl_query := $$ SELECT de.id, de.source, de.field, evergreen.escape_for_html(de.value) AS value, ts_headline( ts_config::REGCONFIG, evergreen.escape_for_html(de.value), $$ || quote_literal(tsq) || $$, $1 || ' ' || mf.field_class || ' ' || mf.name || $xx$'>"$xx$ -- "' ) AS highlight FROM metabib.display_entry de JOIN config.metabib_field mf ON (mf.id = de.field) JOIN search.best_tsconfig t ON (t.id = de.field) WHERE de.source = $2 AND field = ANY ($3) ORDER BY de.id;$$; RETURN QUERY EXECUTE hl_query USING opts, rid, v_field_list; END;
Function: search.symspell_build_entries(include_phrases text, old_input text, source_class text, full_input boolean)
Returns: SET OF symspell_dictionary
Language: PLPGSQL
DECLARE prefix_length INT; maxED INT; word_list TEXT[]; input TEXT; word TEXT; entry search.symspell_dictionary; BEGIN IF full_input IS NOT NULL THEN SELECT value::INT INTO prefix_length FROM config.internal_flag WHERE name = 'symspell.prefix_length' AND enabled; prefix_length := COALESCE(prefix_length, 6); SELECT value::INT INTO maxED FROM config.internal_flag WHERE name = 'symspell.max_edit_distance' AND enabled; maxED := COALESCE(maxED, 3); input := evergreen.lowercase(full_input); word_list := ARRAY_AGG(x) FROM search.symspell_parse_words_distinct(input) x; IF word_list IS NULL THEN RETURN; END IF; IF CARDINALITY(word_list) > 1 AND include_phrases THEN RETURN QUERY SELECT * FROM search.symspell_build_raw_entry(input, source_class, TRUE, prefix_length, maxED); END IF; FOREACH word IN ARRAY word_list LOOP -- Skip words that have runs of 5 or more digits (I'm looking at you, ISxNs) CONTINUE WHEN CHARACTER_LENGTH(word) > 4 AND word ~ '\d{5,}'; RETURN QUERY SELECT * FROM search.symspell_build_raw_entry(word, source_class, FALSE, prefix_length, maxED); END LOOP; END IF; IF old_input IS NOT NULL THEN input := evergreen.lowercase(old_input); FOR word IN SELECT x FROM search.symspell_parse_words_distinct(input) x LOOP -- similarly skip words that have 5 or more digits here to -- avoid adding erroneous prefix deletion entries to the dictionary CONTINUE WHEN CHARACTER_LENGTH(word) > 4 AND word ~ '\d{5,}'; entry.prefix_key := word; entry.keyword_count := 0; entry.title_count := 0; entry.author_count := 0; entry.subject_count := 0; entry.series_count := 0; entry.identifier_count := 0; entry.keyword_suggestions := '{}'; entry.title_suggestions := '{}'; entry.author_suggestions := '{}'; entry.subject_suggestions := '{}'; entry.series_suggestions := '{}'; entry.identifier_suggestions := '{}'; IF source_class = 'keyword' THEN entry.keyword_count := -1; END IF; IF source_class = 'title' THEN entry.title_count := -1; END IF; IF source_class = 'author' THEN entry.author_count := -1; END IF; IF source_class = 'subject' THEN entry.subject_count := -1; END IF; IF source_class = 'series' THEN entry.series_count := -1; END IF; IF source_class = 'identifier' THEN entry.identifier_count := -1; END IF; RETURN NEXT entry; END LOOP; END IF; END;
Function: search.symspell_build_raw_entry(maxed text, prefix_length text, no_limit boolean, source_class integer, raw_input integer)
Returns: SET OF symspell_dictionary
Language: PLPGSQL
DECLARE key TEXT; del_key TEXT; key_list TEXT[]; entry search.symspell_dictionary%ROWTYPE; BEGIN key := raw_input; IF NOT no_limit AND CHARACTER_LENGTH(raw_input) > prefix_length THEN key := SUBSTRING(key FROM 1 FOR prefix_length); key_list := ARRAY[raw_input, key]; ELSE key_list := ARRAY[key]; END IF; FOREACH del_key IN ARRAY key_list LOOP -- skip empty keys CONTINUE WHEN del_key IS NULL OR CHARACTER_LENGTH(del_key) = 0; entry.prefix_key := del_key; entry.keyword_count := 0; entry.title_count := 0; entry.author_count := 0; entry.subject_count := 0; entry.series_count := 0; entry.identifier_count := 0; entry.keyword_suggestions := '{}'; entry.title_suggestions := '{}'; entry.author_suggestions := '{}'; entry.subject_suggestions := '{}'; entry.series_suggestions := '{}'; entry.identifier_suggestions := '{}'; IF source_class = 'keyword' THEN entry.keyword_suggestions := ARRAY[raw_input]; END IF; IF source_class = 'title' THEN entry.title_suggestions := ARRAY[raw_input]; END IF; IF source_class = 'author' THEN entry.author_suggestions := ARRAY[raw_input]; END IF; IF source_class = 'subject' THEN entry.subject_suggestions := ARRAY[raw_input]; END IF; IF source_class = 'series' THEN entry.series_suggestions := ARRAY[raw_input]; END IF; IF source_class = 'identifier' THEN entry.identifier_suggestions := ARRAY[raw_input]; END IF; IF source_class = 'keyword' THEN entry.keyword_suggestions := ARRAY[raw_input]; END IF; IF del_key = raw_input THEN IF source_class = 'keyword' THEN entry.keyword_count := 1; END IF; IF source_class = 'title' THEN entry.title_count := 1; END IF; IF source_class = 'author' THEN entry.author_count := 1; END IF; IF source_class = 'subject' THEN entry.subject_count := 1; END IF; IF source_class = 'series' THEN entry.series_count := 1; END IF; IF source_class = 'identifier' THEN entry.identifier_count := 1; END IF; END IF; RETURN NEXT entry; END LOOP; FOR del_key IN SELECT x FROM UNNEST(search.symspell_generate_edits(key, 1, maxED)) x LOOP -- skip empty keys CONTINUE WHEN del_key IS NULL OR CHARACTER_LENGTH(del_key) = 0; -- skip suggestions that are already too long for the prefix key CONTINUE WHEN CHARACTER_LENGTH(del_key) <= (prefix_length - maxED) AND CHARACTER_LENGTH(raw_input) > prefix_length; entry.keyword_suggestions := '{}'; entry.title_suggestions := '{}'; entry.author_suggestions := '{}'; entry.subject_suggestions := '{}'; entry.series_suggestions := '{}'; entry.identifier_suggestions := '{}'; IF source_class = 'keyword' THEN entry.keyword_count := 0; END IF; IF source_class = 'title' THEN entry.title_count := 0; END IF; IF source_class = 'author' THEN entry.author_count := 0; END IF; IF source_class = 'subject' THEN entry.subject_count := 0; END IF; IF source_class = 'series' THEN entry.series_count := 0; END IF; IF source_class = 'identifier' THEN entry.identifier_count := 0; END IF; entry.prefix_key := del_key; IF source_class = 'keyword' THEN entry.keyword_suggestions := ARRAY[raw_input]; END IF; IF source_class = 'title' THEN entry.title_suggestions := ARRAY[raw_input]; END IF; IF source_class = 'author' THEN entry.author_suggestions := ARRAY[raw_input]; END IF; IF source_class = 'subject' THEN entry.subject_suggestions := ARRAY[raw_input]; END IF; IF source_class = 'series' THEN entry.series_suggestions := ARRAY[raw_input]; END IF; IF source_class = 'identifier' THEN entry.identifier_suggestions := ARRAY[raw_input]; END IF; IF source_class = 'keyword' THEN entry.keyword_suggestions := ARRAY[raw_input]; END IF; RETURN NEXT entry; END LOOP; END;
Function: search.symspell_dictionary_full_reify()
Returns: SET OF symspell_dictionary
Language: SQL
WITH new_rows AS ( DELETE FROM search.symspell_dictionary_updates RETURNING * ), computed_rows AS ( -- this collapses the rows deleted into the format we need for UPSERT SELECT SUM(keyword_count) AS keyword_count, SUM(title_count) AS title_count, SUM(author_count) AS author_count, SUM(subject_count) AS subject_count, SUM(series_count) AS series_count, SUM(identifier_count) AS identifier_count, prefix_key, ARRAY_REMOVE(ARRAY_AGG(DISTINCT keyword_suggestions[1]), NULL) AS keyword_suggestions, ARRAY_REMOVE(ARRAY_AGG(DISTINCT title_suggestions[1]), NULL) AS title_suggestions, ARRAY_REMOVE(ARRAY_AGG(DISTINCT author_suggestions[1]), NULL) AS author_suggestions, ARRAY_REMOVE(ARRAY_AGG(DISTINCT subject_suggestions[1]), NULL) AS subject_suggestions, ARRAY_REMOVE(ARRAY_AGG(DISTINCT series_suggestions[1]), NULL) AS series_suggestions, ARRAY_REMOVE(ARRAY_AGG(DISTINCT identifier_suggestions[1]), NULL) AS identifier_suggestions FROM new_rows GROUP BY prefix_key ) INSERT INTO search.symspell_dictionary AS d SELECT * FROM computed_rows ON CONFLICT (prefix_key) DO UPDATE SET keyword_count = GREATEST(0, d.keyword_count + EXCLUDED.keyword_count), keyword_suggestions = evergreen.text_array_merge_unique(EXCLUDED.keyword_suggestions,d.keyword_suggestions), title_count = GREATEST(0, d.title_count + EXCLUDED.title_count), title_suggestions = evergreen.text_array_merge_unique(EXCLUDED.title_suggestions,d.title_suggestions), author_count = GREATEST(0, d.author_count + EXCLUDED.author_count), author_suggestions = evergreen.text_array_merge_unique(EXCLUDED.author_suggestions,d.author_suggestions), subject_count = GREATEST(0, d.subject_count + EXCLUDED.subject_count), subject_suggestions = evergreen.text_array_merge_unique(EXCLUDED.subject_suggestions,d.subject_suggestions), series_count = GREATEST(0, d.series_count + EXCLUDED.series_count), series_suggestions = evergreen.text_array_merge_unique(EXCLUDED.series_suggestions,d.series_suggestions), identifier_count = GREATEST(0, d.identifier_count + EXCLUDED.identifier_count), identifier_suggestions = evergreen.text_array_merge_unique(EXCLUDED.identifier_suggestions,d.identifier_suggestions) RETURNING *;
Function: search.symspell_dictionary_reify()
Returns: SET OF symspell_dictionary
Language: SQL
WITH new_rows AS ( DELETE FROM search.symspell_dictionary_updates WHERE transaction_id = txid_current() RETURNING * ), computed_rows AS ( -- this collapses the rows deleted into the format we need for UPSERT SELECT SUM(keyword_count) AS keyword_count, SUM(title_count) AS title_count, SUM(author_count) AS author_count, SUM(subject_count) AS subject_count, SUM(series_count) AS series_count, SUM(identifier_count) AS identifier_count, prefix_key, ARRAY_REMOVE(ARRAY_AGG(DISTINCT keyword_suggestions[1]), NULL) AS keyword_suggestions, ARRAY_REMOVE(ARRAY_AGG(DISTINCT title_suggestions[1]), NULL) AS title_suggestions, ARRAY_REMOVE(ARRAY_AGG(DISTINCT author_suggestions[1]), NULL) AS author_suggestions, ARRAY_REMOVE(ARRAY_AGG(DISTINCT subject_suggestions[1]), NULL) AS subject_suggestions, ARRAY_REMOVE(ARRAY_AGG(DISTINCT series_suggestions[1]), NULL) AS series_suggestions, ARRAY_REMOVE(ARRAY_AGG(DISTINCT identifier_suggestions[1]), NULL) AS identifier_suggestions FROM new_rows GROUP BY prefix_key ) INSERT INTO search.symspell_dictionary AS d SELECT * FROM computed_rows ON CONFLICT (prefix_key) DO UPDATE SET keyword_count = GREATEST(0, d.keyword_count + EXCLUDED.keyword_count), keyword_suggestions = evergreen.text_array_merge_unique(EXCLUDED.keyword_suggestions,d.keyword_suggestions), title_count = GREATEST(0, d.title_count + EXCLUDED.title_count), title_suggestions = evergreen.text_array_merge_unique(EXCLUDED.title_suggestions,d.title_suggestions), author_count = GREATEST(0, d.author_count + EXCLUDED.author_count), author_suggestions = evergreen.text_array_merge_unique(EXCLUDED.author_suggestions,d.author_suggestions), subject_count = GREATEST(0, d.subject_count + EXCLUDED.subject_count), subject_suggestions = evergreen.text_array_merge_unique(EXCLUDED.subject_suggestions,d.subject_suggestions), series_count = GREATEST(0, d.series_count + EXCLUDED.series_count), series_suggestions = evergreen.text_array_merge_unique(EXCLUDED.series_suggestions,d.series_suggestions), identifier_count = GREATEST(0, d.identifier_count + EXCLUDED.identifier_count), identifier_suggestions = evergreen.text_array_merge_unique(EXCLUDED.identifier_suggestions,d.identifier_suggestions) WHERE ( EXCLUDED.keyword_count <> 0 OR EXCLUDED.title_count <> 0 OR EXCLUDED.author_count <> 0 OR EXCLUDED.subject_count <> 0 OR EXCLUDED.series_count <> 0 OR EXCLUDED.identifier_count <> 0 OR NOT (EXCLUDED.keyword_suggestions <@ d.keyword_suggestions) OR NOT (EXCLUDED.title_suggestions <@ d.title_suggestions) OR NOT (EXCLUDED.author_suggestions <@ d.author_suggestions) OR NOT (EXCLUDED.subject_suggestions <@ d.subject_suggestions) OR NOT (EXCLUDED.series_suggestions <@ d.series_suggestions) OR NOT (EXCLUDED.identifier_suggestions <@ d.identifier_suggestions) ) RETURNING *;
Function: search.symspell_generate_edits(maxed text, dist integer, raw_word integer)
Returns: text[]
Language: PLPGSQL
DECLARE item TEXT; list TEXT[] := '{}'; sublist TEXT[] := '{}'; BEGIN FOR I IN 1 .. CHARACTER_LENGTH(raw_word) LOOP item := SUBSTRING(raw_word FROM 1 FOR I - 1) || SUBSTRING(raw_word FROM I + 1); IF NOT list @> ARRAY[item] THEN list := item || list; IF dist < maxED AND CHARACTER_LENGTH(raw_word) > dist + 1 THEN sublist := search.symspell_generate_edits(item, dist + 1, maxED) || sublist; END IF; END IF; END LOOP; IF dist = 1 THEN RETURN evergreen.text_array_merge_unique(list, sublist); ELSE RETURN list || sublist; END IF; END;
Function: search.symspell_lookup(kbdist_weight text, pg_trgm_weight text, soundex_weight integer, count_threshold boolean, xfer_case integer, verbosity integer, search_class integer, raw_input integer)
Returns: SET OF symspell_lookup_output
Language: PLPGSQL
DECLARE prefix_length INT; maxED INT; good_suggs HSTORE; word_list TEXT[]; edit_list TEXT[] := '{}'; seen_list TEXT[] := '{}'; output search.symspell_lookup_output; output_list search.symspell_lookup_output[]; entry RECORD; entry_key TEXT; prefix_key TEXT; sugg TEXT; input TEXT; word TEXT; w_pos INT := -1; smallest_ed INT := -1; global_ed INT; i_len INT; l_maxED INT; BEGIN SELECT value::INT INTO prefix_length FROM config.internal_flag WHERE name = 'symspell.prefix_length' AND enabled; prefix_length := COALESCE(prefix_length, 6); SELECT value::INT INTO maxED FROM config.internal_flag WHERE name = 'symspell.max_edit_distance' AND enabled; maxED := COALESCE(maxED, 3); word_list := ARRAY_AGG(x) FROM search.symspell_parse_words(raw_input) x; -- Common case exact match test for preformance IF verbosity = 0 AND CARDINALITY(word_list) = 1 AND CHARACTER_LENGTH(word_list[1]) <= prefix_length THEN EXECUTE 'SELECT '||search_class||'_suggestions AS suggestions, '||search_class||'_count AS count, prefix_key FROM search.symspell_dictionary WHERE prefix_key = $1 AND '||search_class||'_count >= $2 AND '||search_class||'_suggestions @> ARRAY[$1]' INTO entry USING evergreen.lowercase(word_list[1]), COALESCE(count_threshold,1); IF entry.prefix_key IS NOT NULL THEN output.lev_distance := 0; -- definitionally output.prefix_key := entry.prefix_key; output.prefix_key_count := entry.count; output.suggestion_count := entry.count; output.input := word_list[1]; IF xfer_case THEN output.suggestion := search.symspell_transfer_casing(output.input, entry.prefix_key); ELSE output.suggestion := entry.prefix_key; END IF; output.norm_input := entry.prefix_key; output.qwerty_kb_match := 1; output.pg_trgm_sim := 1; output.soundex_sim := 1; RETURN NEXT output; RETURN; END IF; END IF; <<word_loop>> FOREACH word IN ARRAY word_list LOOP w_pos := w_pos + 1; input := evergreen.lowercase(word); i_len := CHARACTER_LENGTH(input); l_maxED := maxED; IF CHARACTER_LENGTH(input) > prefix_length THEN prefix_key := SUBSTRING(input FROM 1 FOR prefix_length); edit_list := ARRAY[input,prefix_key] || search.symspell_generate_edits(prefix_key, 1, l_maxED); ELSE edit_list := input || search.symspell_generate_edits(input, 1, l_maxED); END IF; SELECT ARRAY_AGG(x ORDER BY CHARACTER_LENGTH(x) DESC) INTO edit_list FROM UNNEST(edit_list) x; output_list := '{}'; seen_list := '{}'; global_ed := NULL; <<entry_key_loop>> FOREACH entry_key IN ARRAY edit_list LOOP smallest_ed := -1; IF global_ed IS NOT NULL THEN smallest_ed := global_ed; END IF; FOR entry IN EXECUTE 'SELECT '||search_class||'_suggestions AS suggestions, '||search_class||'_count AS count, prefix_key FROM search.symspell_dictionary WHERE prefix_key = $1 AND '||search_class||'_suggestions IS NOT NULL' USING entry_key LOOP SELECT HSTORE( ARRAY_AGG( ARRAY[s, evergreen.levenshtein_damerau_edistance(input,s,l_maxED)::TEXT] ORDER BY evergreen.levenshtein_damerau_edistance(input,s,l_maxED) DESC ) ) INTO good_suggs FROM UNNEST(entry.suggestions) s WHERE (ABS(CHARACTER_LENGTH(s) - i_len) <= maxEd AND evergreen.levenshtein_damerau_edistance(input,s,l_maxED) BETWEEN 0 AND l_maxED) AND NOT seen_list @> ARRAY[s]; CONTINUE WHEN good_suggs IS NULL; FOR sugg, output.suggestion_count IN EXECUTE 'SELECT prefix_key, '||search_class||'_count FROM search.symspell_dictionary WHERE prefix_key = ANY ($1) AND '||search_class||'_count >= $2' USING AKEYS(good_suggs), COALESCE(count_threshold,1) LOOP output.lev_distance := good_suggs->sugg; seen_list := seen_list || sugg; -- Track the smallest edit distance among suggestions from this prefix key. IF smallest_ed = -1 OR output.lev_distance < smallest_ed THEN smallest_ed := output.lev_distance; END IF; -- Track the smallest edit distance for all prefix keys for this word. IF global_ed IS NULL OR smallest_ed < global_ed THEN global_ed = smallest_ed; -- And if low verbosity, ignore suggs with a larger distance from here on. IF verbosity <= 1 THEN l_maxED := global_ed; END IF; END IF; -- Lev distance is our main similarity measure. While -- trgm or soundex similarity could be the main filter, -- Lev is both language agnostic and faster. -- -- Here we will skip suggestions that have a longer edit distance -- than the shortest we've already found. This is simply an -- optimization that allows us to avoid further processing -- of this entry. It would be filtered out later. CONTINUE WHEN output.lev_distance > global_ed AND verbosity <= 1; -- If we have an exact match on the suggestion key we can also avoid -- some function calls. IF output.lev_distance = 0 THEN output.qwerty_kb_match := 1; output.pg_trgm_sim := 1; output.soundex_sim := 1; ELSE IF kbdist_weight THEN output.qwerty_kb_match := evergreen.qwerty_keyboard_distance_match(input, sugg); ELSE output.qwerty_kb_match := 0; END IF; IF pg_trgm_weight THEN output.pg_trgm_sim := similarity(input, sugg); ELSE output.pg_trgm_sim := 0; END IF; IF soundex_weight THEN output.soundex_sim := difference(input, sugg) / 4.0; ELSE output.soundex_sim := 0; END IF; END IF; -- Fill in some fields IF xfer_case AND input <> word THEN output.suggestion := search.symspell_transfer_casing(word, sugg); ELSE output.suggestion := sugg; END IF; output.prefix_key := entry.prefix_key; output.prefix_key_count := entry.count; output.input := word; output.norm_input := input; output.word_pos := w_pos; -- We can't "cache" a set of generated records directly, so -- here we build up an array of search.symspell_lookup_output -- records that we can revivicate later as a table using UNNEST(). output_list := output_list || output; EXIT entry_key_loop WHEN smallest_ed = 0 AND verbosity = 0; -- exact match early exit CONTINUE entry_key_loop WHEN smallest_ed = 0 AND verbosity = 1; -- exact match early jump to the next key END LOOP; -- loop over suggestions END LOOP; -- loop over entries END LOOP; -- loop over entry_keys -- Now we're done examining this word IF verbosity = 0 THEN -- Return the "best" suggestion from the smallest edit -- distance group. We define best based on the weighting -- of the non-lev similarity measures and use the suggestion -- use count to break ties. RETURN QUERY SELECT * FROM UNNEST(output_list) ORDER BY lev_distance, (soundex_sim * COALESCE(soundex_weight,0)) + (pg_trgm_sim * COALESCE(pg_trgm_weight,0)) + (qwerty_kb_match * COALESCE(kbdist_weight,0)) DESC, suggestion_count DESC LIMIT 1; ELSIF verbosity = 1 THEN -- Return all suggestions from the smallest -- edit distance group. RETURN QUERY SELECT * FROM UNNEST(output_list) WHERE lev_distance = smallest_ed ORDER BY (soundex_sim * COALESCE(soundex_weight,0)) + (pg_trgm_sim * COALESCE(pg_trgm_weight,0)) + (qwerty_kb_match * COALESCE(kbdist_weight,0)) DESC, suggestion_count DESC; ELSIF verbosity = 2 THEN -- Return everything we find, along with relevant stats RETURN QUERY SELECT * FROM UNNEST(output_list) ORDER BY lev_distance, (soundex_sim * COALESCE(soundex_weight,0)) + (pg_trgm_sim * COALESCE(pg_trgm_weight,0)) + (qwerty_kb_match * COALESCE(kbdist_weight,0)) DESC, suggestion_count DESC; ELSIF verbosity = 3 THEN -- Return everything we find from the two smallest edit distance groups RETURN QUERY SELECT * FROM UNNEST(output_list) WHERE lev_distance IN (SELECT DISTINCT lev_distance FROM UNNEST(output_list) ORDER BY 1 LIMIT 2) ORDER BY lev_distance, (soundex_sim * COALESCE(soundex_weight,0)) + (pg_trgm_sim * COALESCE(pg_trgm_weight,0)) + (qwerty_kb_match * COALESCE(kbdist_weight,0)) DESC, suggestion_count DESC; ELSIF verbosity = 4 THEN -- Return everything we find from the two smallest edit distance groups that are NOT 0 distance RETURN QUERY SELECT * FROM UNNEST(output_list) WHERE lev_distance IN (SELECT DISTINCT lev_distance FROM UNNEST(output_list) WHERE lev_distance > 0 ORDER BY 1 LIMIT 2) ORDER BY lev_distance, (soundex_sim * COALESCE(soundex_weight,0)) + (pg_trgm_sim * COALESCE(pg_trgm_weight,0)) + (qwerty_kb_match * COALESCE(kbdist_weight,0)) DESC, suggestion_count DESC; END IF; END LOOP; -- loop over words END;
Function: search.symspell_maintain_entries()
Returns: trigger
Language: PLPGSQL
DECLARE search_class TEXT; new_value TEXT := NULL; old_value TEXT := NULL; BEGIN search_class := COALESCE(TG_ARGV[0], SPLIT_PART(TG_TABLE_NAME,'_',1)); IF TG_OP IN ('INSERT', 'UPDATE') THEN new_value := NEW.value; END IF; IF TG_OP IN ('DELETE', 'UPDATE') THEN old_value := OLD.value; END IF; IF new_value = old_value THEN -- same, move along ELSE INSERT INTO search.symspell_dictionary_updates SELECT txid_current(), * FROM search.symspell_build_entries( new_value, search_class, old_value ); END IF; RETURN NULL; -- always fired AFTER END;
Function: search.symspell_parse_words(phrase text)
Returns: SET OF text
Language: SQL
SELECT UNNEST(x) FROM regexp_matches($1, '([[:alnum:]]+''*[[:alnum:]]*)', 'g') x;
Function: search.symspell_parse_words_distinct(phrase text)
Returns: SET OF text
Language: SQL
SELECT DISTINCT UNNEST(x) FROM regexp_matches($1, '([[:alnum:]]+''*[[:alnum:]]*)', 'g') x;
Function: search.symspell_transfer_casing(withoutcase text, withcase text)
Returns: text
Language: PLPGSQL
DECLARE woChars TEXT[]; curr TEXT; ind INT := 1; BEGIN woChars := regexp_split_to_array(withoutCase,''); FOR curr IN SELECT x FROM regexp_split_to_table(withCase, '') x LOOP IF curr = evergreen.uppercase(curr) THEN woChars[ind] := evergreen.uppercase(woChars[ind]); END IF; ind := ind + 1; END LOOP; RETURN ARRAY_TO_STRING(woChars,''); END;
Schema serial
View: serial.any_summary
F-Key | Name | Type | Description |
---|---|---|---|
summary_type | text | ||
id | integer | ||
distribution | integer | ||
generated_coverage | text | ||
textual_holdings | text | ||
show_generated | boolean |
SELECT'basic'::text AS summary_type , basic_summary.id , basic_summary.distribution , basic_summary.generated_coverage , basic_summary.textual_holdings , basic_summary.show_generated FROM serial.basic_summary UNION SELECT'index'::text AS summary_type , index_summary.id , index_summary.distribution , index_summary.generated_coverage , index_summary.textual_holdings , index_summary.show_generated FROM serial.index_summary UNION SELECT'supplement'::text AS summary_type , supplement_summary.id , supplement_summary.distribution , supplement_summary.generated_coverage , supplement_summary.textual_holdings , supplement_summary.show_generated FROM serial.supplement_summary;
Table: serial.basic_summary
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
serial.distribution.id | distribution | integer | NOT NULL |
generated_coverage | text | NOT NULL | |
textual_holdings | text | ||
show_generated | boolean | NOT NULL DEFAULT true |
Table: serial.caption_and_pattern
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
serial.subscription.id | subscription | integer | NOT NULL |
type | text | NOT NULL | |
create_date | timestamp with time zone | NOT NULL DEFAULT now() | |
start_date | timestamp with time zone | NOT NULL DEFAULT now() | |
end_date | timestamp with time zone | ||
active | boolean | NOT NULL DEFAULT false | |
pattern_code | text | NOT NULL | |
enum_1 | text | ||
enum_2 | text | ||
enum_3 | text | ||
enum_4 | text | ||
enum_5 | text | ||
enum_6 | text | ||
chron_1 | text | ||
chron_2 | text | ||
chron_3 | text | ||
chron_4 | text | ||
chron_5 | text |
Name | Constraint |
---|---|
cap_type | CHECK ((type = ANY (ARRAY['basic'::text, 'supplement'::text, 'index'::text]))) |
Tables referencing this one via Foreign Key Constraints:
serial_caption_and_pattern_sub_idx subscriptionTable: serial.distribution
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
serial.record_entry.id | record_entry | bigint | |
summary_method | text | ||
serial.subscription.id | subscription | integer | NOT NULL |
actor.org_unit.id | holding_lib | integer | NOT NULL |
label | text | NOT NULL | |
display_grouping | text | NOT NULL DEFAULT 'chron'::text | |
asset.call_number.id | receive_call_number | bigint | |
asset.copy_template.id | receive_unit_template | integer | |
asset.call_number.id | bind_call_number | bigint | |
asset.copy_template.id | bind_unit_template | integer | |
unit_label_prefix | text | ||
unit_label_suffix | text |
Name | Constraint |
---|---|
distribution_display_grouping_check | CHECK ((display_grouping = ANY (ARRAY['enum'::text, 'chron'::text]))) |
sdist_summary_method_check | CHECK (((summary_method IS NULL) OR (summary_method = ANY (ARRAY['add_to_sre'::text, 'merge_with_sre'::text, 'use_sre_only'::text, 'use_sdist_only'::text])))) |
Tables referencing this one via Foreign Key Constraints:
serial_distribution_holding_lib_idx holding_lib serial_distribution_sub_idx subscriptionTable: serial.distribution_note
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
serial.distribution.id | distribution | integer | NOT NULL |
actor.usr.id | creator | integer | NOT NULL |
create_date | timestamp with time zone | DEFAULT now() | |
pub | boolean | NOT NULL DEFAULT false | |
alert | boolean | NOT NULL DEFAULT false | |
title | text | NOT NULL | |
value | text | NOT NULL |
Table: serial.index_summary
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
serial.distribution.id | distribution | integer | NOT NULL |
generated_coverage | text | NOT NULL | |
textual_holdings | text | ||
show_generated | boolean | NOT NULL DEFAULT true |
Table: serial.issuance
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.usr.id | creator | integer | NOT NULL |
actor.usr.id | editor | integer | NOT NULL |
create_date | timestamp with time zone | NOT NULL DEFAULT now() | |
edit_date | timestamp with time zone | NOT NULL DEFAULT now() | |
serial.subscription.id | subscription | integer | NOT NULL |
label | text | ||
date_published | timestamp with time zone | ||
serial.caption_and_pattern.id | caption_and_pattern | integer | |
holding_code | text | ||
holding_type | text | ||
holding_link_id | integer |
Name | Constraint |
---|---|
issuance_holding_code_check | CHECK (((holding_code IS NULL) OR could_be_serial_holding_code(holding_code))) |
issuance_holding_code_check1 | CHECK (((holding_code IS NULL) OR is_json(holding_code))) |
valid_holding_type | CHECK (((holding_type IS NULL) OR (holding_type = ANY (ARRAY['basic'::text, 'supplement'::text, 'index'::text])))) |
Tables referencing this one via Foreign Key Constraints:
serial_issuance_caption_and_pattern_idx caption_and_pattern serial_issuance_date_published_idx date_published serial_issuance_sub_idx subscriptionTable: serial.item
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.usr.id | creator | integer | NOT NULL |
actor.usr.id | editor | integer | NOT NULL |
create_date | timestamp with time zone | NOT NULL DEFAULT now() | |
edit_date | timestamp with time zone | NOT NULL DEFAULT now() | |
serial.issuance.id | issuance | integer | NOT NULL |
serial.stream.id | stream | integer | NOT NULL |
serial.unit.id | unit | integer | |
asset.uri.id | uri | integer | |
date_expected | timestamp with time zone | ||
date_received | timestamp with time zone | ||
status | text | DEFAULT 'Expected'::text | |
shadowed | boolean | NOT NULL DEFAULT false |
Name | Constraint |
---|---|
valid_status | CHECK ((status = ANY (ARRAY['Bindery'::text, 'Bound'::text, 'Claimed'::text, 'Discarded'::text, 'Expected'::text, 'Not Held'::text, 'Not Published'::text, 'Received'::text]))) |
Tables referencing this one via Foreign Key Constraints:
serial_item_date_received_idx date_received serial_item_issuance_idx issuance serial_item_status_idx status serial_item_stream_idx stream serial_item_unit_idx unit serial_item_uri_idx uriTable: serial.item_note
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
serial.item.id | item | integer | NOT NULL |
actor.usr.id | creator | integer | NOT NULL |
create_date | timestamp with time zone | DEFAULT now() | |
pub | boolean | NOT NULL DEFAULT false | |
alert | boolean | NOT NULL DEFAULT false | |
title | text | NOT NULL | |
value | text | NOT NULL |
Table: serial.materialized_holding_code
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
serial.issuance.id | issuance | integer | NOT NULL |
subfield | character(1) | ||
value | text |
Table: serial.pattern_template
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | NOT NULL | |
pattern_code | text | NOT NULL | |
actor.org_unit.id | owning_lib | integer | |
share_depth | integer | NOT NULL |
Table: serial.record_entry
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
biblio.record_entry.id | record | bigint | |
actor.org_unit.id | owning_lib | integer | NOT NULL DEFAULT 1 |
creator | integer | NOT NULL DEFAULT 1 | |
editor | integer | NOT NULL DEFAULT 1 | |
source | integer | ||
create_date | timestamp with time zone | NOT NULL DEFAULT now() | |
edit_date | timestamp with time zone | NOT NULL DEFAULT now() | |
active | boolean | NOT NULL DEFAULT true | |
deleted | boolean | NOT NULL DEFAULT false | |
marc | text | ||
last_xact_id | text | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
serial_record_entry_creator_idx creator serial_record_entry_editor_idx editor serial_record_entry_owning_lib_idx owning_lib, deleted serial_record_entry_record_idx recordTable: serial.routing_list_user
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
serial.stream.id | stream | integer | UNIQUE#1 NOT NULL |
pos | integer | UNIQUE#1 NOT NULL DEFAULT 1 | |
actor.usr.id | reader | integer | |
department | text | ||
note | text |
Name | Constraint |
---|---|
reader_or_dept | CHECK ((((reader IS NOT NULL) AND (department IS NULL)) OR ((reader IS NULL) AND (department IS NOT NULL)))) |
Table: serial.stream
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
serial.distribution.id | distribution | integer | NOT NULL |
routing_label | text |
Tables referencing this one via Foreign Key Constraints:
serial_stream_dist_idx distributionTable: serial.subscription
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | owning_lib | integer | NOT NULL DEFAULT 1 |
start_date | timestamp with time zone | NOT NULL | |
end_date | timestamp with time zone | ||
biblio.record_entry.id | record_entry | bigint | |
expected_date_offset | interval |
Tables referencing this one via Foreign Key Constraints:
serial_subscription_owner_idx owning_lib serial_subscription_record_idx record_entryTable: serial.subscription_note
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
serial.subscription.id | subscription | integer | NOT NULL |
actor.usr.id | creator | integer | NOT NULL |
create_date | timestamp with time zone | DEFAULT now() | |
pub | boolean | NOT NULL DEFAULT false | |
alert | boolean | NOT NULL DEFAULT false | |
title | text | NOT NULL | |
value | text | NOT NULL |
Table: serial.supplement_summary
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
serial.distribution.id | distribution | integer | NOT NULL |
generated_coverage | text | NOT NULL | |
textual_holdings | text | ||
show_generated | boolean | NOT NULL DEFAULT true |
Table: serial.unit
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY DEFAULT nextval('asset.copy_id_seq'::regclass) | |
circ_lib | integer | NOT NULL | |
actor.usr.id | creator | bigint | NOT NULL |
asset.call_number.id | call_number | bigint | NOT NULL |
actor.usr.id | editor | bigint | NOT NULL |
create_date | timestamp with time zone | DEFAULT now() | |
edit_date | timestamp with time zone | DEFAULT now() | |
copy_number | integer | ||
status | integer | NOT NULL | |
location | integer | NOT NULL DEFAULT 1 | |
loan_duration | integer | NOT NULL | |
fine_level | integer | NOT NULL | |
age_protect | integer | ||
circulate | boolean | NOT NULL DEFAULT true | |
deposit | boolean | NOT NULL DEFAULT false | |
ref | boolean | NOT NULL DEFAULT false | |
holdable | boolean | NOT NULL DEFAULT true | |
deposit_amount | numeric(6,2) | NOT NULL DEFAULT 0.00 | |
price | numeric(8,2) | ||
barcode | text | NOT NULL | |
circ_modifier | text | ||
circ_as_type | text | ||
dummy_title | text | ||
dummy_author | text | ||
alert_message | text | ||
opac_visible | boolean | NOT NULL DEFAULT true | |
deleted | boolean | NOT NULL DEFAULT false | |
floating | integer | ||
dummy_isbn | text | ||
status_changed_time | timestamp with time zone | ||
active_date | timestamp with time zone | ||
mint_condition | boolean | NOT NULL DEFAULT true | |
cost | numeric(8,2) | ||
sort_key | text | ||
detailed_contents | text | NOT NULL | |
summary_contents | text | NOT NULL |
Table serial.unit Inherits copy,
Name | Constraint |
---|---|
copy_fine_level_check | CHECK ((fine_level = ANY (ARRAY[1, 2, 3]))) |
copy_loan_duration_check | CHECK ((loan_duration = ANY (ARRAY[1, 2, 3]))) |
Tables referencing this one via Foreign Key Constraints:
unit_avail_cn_idx call_number unit_cn_idx call_number unit_creator_idx creator unit_editor_idx editorFunction: serial.materialize_holding_code()
Returns: trigger
Language: PLPERLU
use strict; use MARC::Field; use JSON::XS; if (not defined $_TD->{new}{holding_code}) { elog(WARNING, 'NULL in "holding_code" column of serial.issuance allowed for now, but may not be useful'); return; } # Do nothing if holding_code has not changed... if ($_TD->{new}{holding_code} eq $_TD->{old}{holding_code}) { # ... unless the following internal flag is set. my $flag_rv = spi_exec_query(q{ SELECT * FROM config.internal_flag WHERE name = 'serial.rematerialize_on_same_holding_code' AND enabled }, 1); return unless $flag_rv->{processed}; } my $holding_code = (new JSON::XS)->decode($_TD->{new}{holding_code}); my $field = new MARC::Field('999', @$holding_code); # tag doesnt matter my $dstmt = spi_prepare( 'DELETE FROM serial.materialized_holding_code WHERE issuance = $1', 'INT' ); spi_exec_prepared($dstmt, $_TD->{new}{id}); my $istmt = spi_prepare( q{ INSERT INTO serial.materialized_holding_code ( issuance, subfield, value ) VALUES ($1, $2, $3) }, qw{INT CHAR TEXT} ); foreach ($field->subfields) { spi_exec_prepared( $istmt, $_TD->{new}{id}, $_->[0], $_->[1] ); } return;
Function: serial.pattern_templates_visible_to(org_unit integer)
Returns: SET OF pattern_template
Language: PLPGSQL
BEGIN RETURN QUERY SELECT * FROM serial.pattern_template spt WHERE ( SELECT ARRAY_AGG(id) FROM actor.org_unit_descendants(spt.owning_lib, spt.share_depth) ) @@ org_unit::TEXT::QUERY_INT; END;
Schema staging
Table: staging.billing_address_stage
F-Key | Name | Type | Description |
---|---|---|---|
row_id | bigint | PRIMARY KEY DEFAULT nextval('staging.mailing_address_stage_row_id_seq'::regclass) | |
row_date | timestamp with time zone | DEFAULT now() | |
usrname | text | NOT NULL | |
street1 | text | ||
street2 | text | ||
city | text | NOT NULL DEFAULT ''::text | |
county | text | ||
state | text | ||
country | text | NOT NULL DEFAULT 'US'::text | |
post_code | text | NOT NULL | |
complete | boolean | DEFAULT false |
Table: staging.card_stage
F-Key | Name | Type | Description |
---|---|---|---|
row_id | bigserial | PRIMARY KEY | |
row_date | timestamp with time zone | DEFAULT now() | |
usrname | text | NOT NULL | |
barcode | text | NOT NULL | |
complete | boolean | DEFAULT false |
Table: staging.mailing_address_stage
F-Key | Name | Type | Description |
---|---|---|---|
row_id | bigserial | PRIMARY KEY | |
row_date | timestamp with time zone | DEFAULT now() | |
usrname | text | NOT NULL | |
street1 | text | ||
street2 | text | ||
city | text | NOT NULL DEFAULT ''::text | |
county | text | ||
state | text | ||
country | text | NOT NULL DEFAULT 'US'::text | |
post_code | text | NOT NULL | |
complete | boolean | DEFAULT false |
Table: staging.setting_stage
F-Key | Name | Type | Description |
---|---|---|---|
row_id | bigserial | PRIMARY KEY | |
row_date | timestamp with time zone | DEFAULT now() | |
usrname | text | NOT NULL | |
setting | text | NOT NULL | |
value | text | NOT NULL | |
complete | boolean | DEFAULT false |
Table: staging.statcat_stage
F-Key | Name | Type | Description |
---|---|---|---|
row_id | bigserial | PRIMARY KEY | |
row_date | timestamp with time zone | DEFAULT now() | |
usrname | text | NOT NULL | |
statcat | text | NOT NULL | |
value | text | NOT NULL | |
complete | boolean | DEFAULT false |
Table: staging.user_stage
F-Key | Name | Type | Description |
---|---|---|---|
row_id | bigserial | PRIMARY KEY | |
row_date | timestamp with time zone | DEFAULT now() | |
usrname | text | NOT NULL | |
profile | text | ||
text | |||
passwd | text | ||
ident_type | integer | DEFAULT 3 | |
first_given_name | text | ||
second_given_name | text | ||
family_name | text | ||
pref_first_given_name | text | ||
pref_second_given_name | text | ||
pref_family_name | text | ||
day_phone | text | ||
evening_phone | text | ||
home_ou | integer | DEFAULT 2 | |
dob | text | ||
complete | boolean | DEFAULT false | |
actor.usr.id | requesting_usr | integer |
Function: staging.purge_pending_users()
Returns: void
Language: PLPGSQL
DECLARE org_id INT; intvl TEXT; BEGIN FOR org_id IN SELECT DISTINCT(home_ou) FROM staging.user_stage LOOP SELECT INTO intvl value FROM actor.org_unit_ancestor_setting( 'opac.pending_user_expire_interval', org_id); CONTINUE WHEN intvl IS NULL OR intvl ILIKE 'null'; -- de-JSON-ify the string SELECT INTO intvl TRIM(BOTH '"' FROM intvl); DELETE FROM staging.user_stage WHERE home_ou = org_id AND row_date + intvl::INTERVAL < NOW(); END LOOP; END;
Schema stats
Schema unapi
Table: unapi.bre_output_layout
F-Key | Name | Type | Description |
---|---|---|---|
name | text | PRIMARY KEY | |
config.xml_transform.name | transform | text | |
mime_type | text | NOT NULL | |
feed_top | text | NOT NULL | |
holdings_element | text | ||
title_element | text | ||
description_element | text | ||
creator_element | text | ||
update_ts_element | text |
Function: unapi.acl(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
Returns: xml
Language: SQL
SELECT XMLELEMENT( name location, XMLATTRIBUTES( CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns, id AS ident, holdable, opac_visible, label_prefix AS prefix, label_suffix AS suffix ), name ) FROM asset.copy_location WHERE id = $1;
Function: unapi.acn(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
Returns: xml
Language: SQL
SELECT XMLELEMENT( name volume, XMLATTRIBUTES( CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns, 'tag:open-ils.org:U2@acn/' || acn.id AS id, acn.id AS vol_id, o.shortname AS lib, o.opac_visible AS opac_visible, deleted, label, label_sortkey, label_class, record ), unapi.aou( owning_lib, $2, 'owning_lib', array_remove($4,'acn'), $5, $6, $7, $8), CASE WHEN ('acp' = ANY ($4)) THEN CASE WHEN $6 IS NOT NULL THEN XMLELEMENT( name copies, (SELECT XMLAGG(acp ORDER BY rank_avail) FROM ( SELECT unapi.acp( cp.id, 'xml', 'copy', array_remove($4,'acn'), $5, $6, $7, $8, FALSE), evergreen.rank_cp(cp) AS rank_avail FROM asset.copy cp JOIN actor.org_unit_descendants( (SELECT id FROM actor.org_unit WHERE shortname = $5), $6) aoud ON (cp.circ_lib = aoud.id) WHERE cp.call_number = acn.id AND cp.deleted IS FALSE ORDER BY rank_avail, COALESCE(cp.copy_number,0), cp.barcode LIMIT ($7 -> 'acp')::INT OFFSET ($8 -> 'acp')::INT )x) ) ELSE XMLELEMENT( name copies, (SELECT XMLAGG(acp ORDER BY rank_avail) FROM ( SELECT unapi.acp( cp.id, 'xml', 'copy', array_remove($4,'acn'), $5, $6, $7, $8, FALSE), evergreen.rank_cp(cp) AS rank_avail FROM asset.copy cp JOIN actor.org_unit_descendants( (SELECT id FROM actor.org_unit WHERE shortname = $5) ) aoud ON (cp.circ_lib = aoud.id) WHERE cp.call_number = acn.id AND cp.deleted IS FALSE ORDER BY rank_avail, COALESCE(cp.copy_number,0), cp.barcode LIMIT ($7 -> 'acp')::INT OFFSET ($8 -> 'acp')::INT )x) ) END ELSE NULL END, XMLELEMENT( name uris, (SELECT XMLAGG(auri) FROM (SELECT unapi.auri(uri,'xml','uri', array_remove($4,'acn'), $5, $6, $7, $8, FALSE) FROM asset.uri_call_number_map WHERE call_number = acn.id)x) ), unapi.acnp( acn.prefix, 'marcxml', 'prefix', array_remove($4,'acn'), $5, $6, $7, $8, FALSE), unapi.acns( acn.suffix, 'marcxml', 'suffix', array_remove($4,'acn'), $5, $6, $7, $8, FALSE), CASE WHEN ('bre' = ANY ($4)) THEN unapi.bre( acn.record, 'marcxml', 'record', array_remove($4,'acn'), $5, $6, $7, $8, FALSE) ELSE NULL END ) AS x FROM asset.call_number acn JOIN actor.org_unit o ON (o.id = acn.owning_lib) WHERE acn.id = $1 AND acn.deleted IS FALSE GROUP BY acn.id, o.shortname, o.opac_visible, deleted, label, label_sortkey, label_class, owning_lib, record, acn.prefix, acn.suffix;
Function: unapi.acnp(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
Returns: xml
Language: SQL
SELECT XMLELEMENT( name call_number_prefix, XMLATTRIBUTES( CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns, id AS ident, label, 'tag:open-ils.org:U2@aou/' || owning_lib AS owning_lib, label_sortkey ) ) FROM asset.call_number_prefix WHERE id = $1;
Function: unapi.acns(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
Returns: xml
Language: SQL
SELECT XMLELEMENT( name call_number_suffix, XMLATTRIBUTES( CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns, id AS ident, label, 'tag:open-ils.org:U2@aou/' || owning_lib AS owning_lib, label_sortkey ) ) FROM asset.call_number_suffix WHERE id = $1;
Function: unapi.acp(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
Returns: xml
Language: SQL
SELECT XMLELEMENT( name copy, XMLATTRIBUTES( CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns, 'tag:open-ils.org:U2@acp/' || id AS id, id AS copy_id, create_date, edit_date, copy_number, circulate, deposit, ref, holdable, deleted, deposit_amount, price, barcode, circ_modifier, circ_as_type, opac_visible, age_protect ), unapi.ccs( status, $2, 'status', array_remove($4,'acp'), $5, $6, $7, $8, FALSE), unapi.acl( location, $2, 'location', array_remove($4,'acp'), $5, $6, $7, $8, FALSE), unapi.aou( circ_lib, $2, 'circ_lib', array_remove($4,'acp'), $5, $6, $7, $8), unapi.aou( circ_lib, $2, 'circlib', array_remove($4,'acp'), $5, $6, $7, $8), CASE WHEN ('acn' = ANY ($4)) THEN unapi.acn( call_number, $2, 'call_number', array_remove($4,'acp'), $5, $6, $7, $8, FALSE) ELSE NULL END, CASE WHEN ('acpn' = ANY ($4)) THEN XMLELEMENT( name copy_notes, (SELECT XMLAGG(acpn) FROM ( SELECT unapi.acpn( id, 'xml', 'copy_note', array_remove($4,'acp'), $5, $6, $7, $8, FALSE) FROM asset.copy_note WHERE owning_copy = cp.id AND pub )x) ) ELSE NULL END, CASE WHEN ('ascecm' = ANY ($4)) THEN XMLELEMENT( name statcats, (SELECT XMLAGG(ascecm) FROM ( SELECT unapi.ascecm( stat_cat_entry, 'xml', 'statcat', array_remove($4,'acp'), $5, $6, $7, $8, FALSE) FROM asset.stat_cat_entry_copy_map WHERE owning_copy = cp.id )x) ) ELSE NULL END, CASE WHEN ('bre' = ANY ($4)) THEN XMLELEMENT( name foreign_records, (SELECT XMLAGG(bre) FROM ( SELECT unapi.bre(peer_record,'marcxml','record','{}'::TEXT[], $5, $6, $7, $8, FALSE) FROM biblio.peer_bib_copy_map WHERE target_copy = cp.id )x) ) ELSE NULL END, CASE WHEN ('bmp' = ANY ($4)) THEN XMLELEMENT( name monograph_parts, (SELECT XMLAGG(bmp) FROM ( SELECT unapi.bmp( part, 'xml', 'monograph_part', array_remove($4,'acp'), $5, $6, $7, $8, FALSE) FROM asset.copy_part_map WHERE target_copy = cp.id )x) ) ELSE NULL END, CASE WHEN ('circ' = ANY ($4)) THEN XMLELEMENT( name current_circulation, (SELECT XMLAGG(circ) FROM ( SELECT unapi.circ( id, 'xml', 'circ', array_remove($4,'circ'), $5, $6, $7, $8, FALSE) FROM action.circulation WHERE target_copy = cp.id AND checkin_time IS NULL )x) ) ELSE NULL END ) FROM asset.copy cp WHERE id = $1 AND cp.deleted IS FALSE GROUP BY id, status, location, circ_lib, call_number, create_date, edit_date, copy_number, circulate, deposit, ref, holdable, deleted, deposit_amount, price, barcode, circ_modifier, circ_as_type, opac_visible, age_protect;
Function: unapi.acpn(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
Returns: xml
Language: SQL
SELECT XMLELEMENT( name copy_note, XMLATTRIBUTES( CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns, create_date AS date, title ), value ) FROM asset.copy_note WHERE id = $1;
Function: unapi.aou(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
Returns: xml
Language: PLPGSQL
DECLARE output XML; BEGIN IF ename = 'circlib' THEN SELECT XMLELEMENT( name circlib, XMLATTRIBUTES( 'http://open-ils.org/spec/actors/v1' AS xmlns, id AS ident ), name ) INTO output FROM actor.org_unit aou WHERE id = obj_id; ELSE EXECUTE $$SELECT XMLELEMENT( name $$ || ename || $$, XMLATTRIBUTES( 'http://open-ils.org/spec/actors/v1' AS xmlns, 'tag:open-ils.org:U2@aou/' || id AS id, shortname, name, opac_visible ) ) FROM actor.org_unit aou WHERE id = $1 $$ INTO output USING obj_id; END IF; RETURN output; END;
Function: unapi.ascecm(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
Returns: xml
Language: SQL
SELECT XMLELEMENT( name statcat, XMLATTRIBUTES( CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns, sc.name, sc.opac_visible ), asce.value ) FROM asset.stat_cat_entry asce JOIN asset.stat_cat sc ON (sc.id = asce.stat_cat) WHERE asce.id = $1;
Function: unapi.auri(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
Returns: xml
Language: SQL
SELECT XMLELEMENT( name uri, XMLATTRIBUTES( CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns, 'tag:open-ils.org:U2@auri/' || uri.id AS id, use_restriction, href, label ), CASE WHEN ('acn' = ANY ($4)) THEN XMLELEMENT( name copies, (SELECT XMLAGG(acn) FROM (SELECT unapi.acn( call_number, 'xml', 'copy', array_remove($4,'auri'), $5, $6, $7, $8, FALSE) FROM asset.uri_call_number_map WHERE uri = uri.id)x) ) ELSE NULL END ) AS x FROM asset.uri uri WHERE uri.id = $1 GROUP BY uri.id, use_restriction, href, label;
Function: unapi.biblio_record_entry_feed(pref_lib bigint[], header_xml text, unapi_url text[], update_ts text, creator integer, description public.hstore, title public.hstore, include_xmlns boolean, soffset text, slimit text, depth text, org text, includes text, format xml, id_list integer)
Returns: xml
Language: PLPGSQL
DECLARE layout unapi.bre_output_layout%ROWTYPE; transform config.xml_transform%ROWTYPE; item_format TEXT; tmp_xml TEXT; xmlns_uri TEXT := 'http://open-ils.org/spec/feed-xml/v1'; ouid INT; element_list TEXT[]; BEGIN IF org = '-' OR org IS NULL THEN SELECT shortname INTO org FROM evergreen.org_top(); END IF; SELECT id INTO ouid FROM actor.org_unit WHERE shortname = org; SELECT * INTO layout FROM unapi.bre_output_layout WHERE name = format; IF layout.name IS NULL THEN RETURN NULL::XML; END IF; SELECT * INTO transform FROM config.xml_transform WHERE name = layout.transform; xmlns_uri := COALESCE(transform.namespace_uri,xmlns_uri); -- Gather the bib xml SELECT XMLAGG( unapi.bre(i, format, '', includes, org, depth, slimit, soffset, include_xmlns, pref_lib)) INTO tmp_xml FROM UNNEST( id_list ) i; IF layout.title_element IS NOT NULL THEN EXECUTE 'SELECT XMLCONCAT( XMLELEMENT( name '|| layout.title_element ||', XMLATTRIBUTES( $1 AS xmlns), $3), $2)' INTO tmp_xml USING xmlns_uri, tmp_xml::XML, title; END IF; IF layout.description_element IS NOT NULL THEN EXECUTE 'SELECT XMLCONCAT( XMLELEMENT( name '|| layout.description_element ||', XMLATTRIBUTES( $1 AS xmlns), $3), $2)' INTO tmp_xml USING xmlns_uri, tmp_xml::XML, description; END IF; IF layout.creator_element IS NOT NULL THEN EXECUTE 'SELECT XMLCONCAT( XMLELEMENT( name '|| layout.creator_element ||', XMLATTRIBUTES( $1 AS xmlns), $3), $2)' INTO tmp_xml USING xmlns_uri, tmp_xml::XML, creator; END IF; IF layout.update_ts_element IS NOT NULL THEN EXECUTE 'SELECT XMLCONCAT( XMLELEMENT( name '|| layout.update_ts_element ||', XMLATTRIBUTES( $1 AS xmlns), $3), $2)' INTO tmp_xml USING xmlns_uri, tmp_xml::XML, update_ts; END IF; IF unapi_url IS NOT NULL THEN EXECUTE $$SELECT XMLCONCAT( XMLELEMENT( name link, XMLATTRIBUTES( 'http://www.w3.org/1999/xhtml' AS xmlns, 'unapi-server' AS rel, $1 AS href, 'unapi' AS title)), $2)$$ INTO tmp_xml USING unapi_url, tmp_xml::XML; END IF; IF header_xml IS NOT NULL THEN tmp_xml := XMLCONCAT(header_xml,tmp_xml::XML); END IF; element_list := regexp_split_to_array(layout.feed_top,E'\\.'); FOR i IN REVERSE ARRAY_UPPER(element_list, 1) .. 1 LOOP EXECUTE 'SELECT XMLELEMENT( name '|| quote_ident(element_list[i]) ||', XMLATTRIBUTES( $1 AS xmlns), $2)' INTO tmp_xml USING xmlns_uri, tmp_xml::XML; END LOOP; RETURN tmp_xml::XML; END;
Function: unapi.bmp(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
Returns: xml
Language: SQL
SELECT XMLELEMENT( name monograph_part, XMLATTRIBUTES( CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns, 'tag:open-ils.org:U2@bmp/' || id AS id, id AS ident, label, label_sortkey, 'tag:open-ils.org:U2@bre/' || record AS record ), CASE WHEN ('acp' = ANY ($4)) THEN XMLELEMENT( name copies, (SELECT XMLAGG(acp) FROM ( SELECT unapi.acp( cp.id, 'xml', 'copy', array_remove($4,'bmp'), $5, $6, $7, $8, FALSE) FROM asset.copy cp JOIN asset.copy_part_map cpm ON (cpm.target_copy = cp.id) WHERE cpm.part = $1 AND cp.deleted IS FALSE ORDER BY COALESCE(cp.copy_number,0), cp.barcode LIMIT ($7 -> 'acp')::INT OFFSET ($8 -> 'acp')::INT )x) ) ELSE NULL END, CASE WHEN ('bre' = ANY ($4)) THEN unapi.bre( record, 'marcxml', 'record', array_remove($4,'bmp'), $5, $6, $7, $8, FALSE) ELSE NULL END ) FROM biblio.monograph_part WHERE NOT deleted AND id = $1 GROUP BY id, label, label_sortkey, record;
Function: unapi.bre(pref_lib bigint, include_xmlns text, soffset text, slimit text[], depth text, org integer, includes public.hstore, ename public.hstore, format boolean, obj_id integer)
Returns: xml
Language: PLPGSQL
DECLARE me biblio.record_entry%ROWTYPE; layout unapi.bre_output_layout%ROWTYPE; xfrm config.xml_transform%ROWTYPE; ouid INT; tmp_xml TEXT; top_el TEXT; output XML; hxml XML; axml XML; source XML; BEGIN IF org = '-' OR org IS NULL THEN SELECT shortname INTO org FROM evergreen.org_top(); END IF; SELECT id INTO ouid FROM actor.org_unit WHERE shortname = org; IF ouid IS NULL THEN RETURN NULL::XML; END IF; IF format = 'holdings_xml' THEN -- the special case output := unapi.holdings_xml( obj_id, ouid, org, depth, includes, slimit, soffset, include_xmlns); RETURN output; END IF; SELECT * INTO layout FROM unapi.bre_output_layout WHERE name = format; IF layout.name IS NULL THEN RETURN NULL::XML; END IF; SELECT * INTO xfrm FROM config.xml_transform WHERE name = layout.transform; SELECT * INTO me FROM biblio.record_entry WHERE id = obj_id; -- grab bib_source, if any IF ('cbs' = ANY (includes) AND me.source IS NOT NULL) THEN source := unapi.cbs(me.source,NULL,NULL,NULL,NULL); ELSE source := NULL::XML; END IF; -- grab SVF if we need them IF ('mra' = ANY (includes)) THEN axml := unapi.mra(obj_id,NULL,NULL,NULL,NULL); ELSE axml := NULL::XML; END IF; -- grab holdings if we need them IF ('holdings_xml' = ANY (includes)) THEN hxml := unapi.holdings_xml(obj_id, ouid, org, depth, array_remove(includes,'holdings_xml'), slimit, soffset, include_xmlns, pref_lib); ELSE hxml := NULL::XML; END IF; -- generate our item node IF format = 'marcxml' THEN tmp_xml := me.marc; IF tmp_xml !~ E'<marc:' THEN -- If we're not using the prefixed namespace in this record, then remove all declarations of it tmp_xml := REGEXP_REPLACE(tmp_xml, ' xmlns:marc="http://www.loc.gov/MARC21/slim"', '', 'g'); END IF; ELSE tmp_xml := oils_xslt_process(me.marc, xfrm.xslt)::XML; END IF; top_el := REGEXP_REPLACE(tmp_xml, E'^.*?<((?:\\S+:)?' || layout.holdings_element || ').*$', E'\\1'); IF source IS NOT NULL THEN tmp_xml := REGEXP_REPLACE(tmp_xml, '</' || top_el || '>(.*?)$', source || '</' || top_el || E'>\\1'); END IF; IF axml IS NOT NULL THEN tmp_xml := REGEXP_REPLACE(tmp_xml, '</' || top_el || '>(.*?)$', axml || '</' || top_el || E'>\\1'); END IF; IF hxml IS NOT NULL THEN -- XXX how do we configure the holdings position? tmp_xml := REGEXP_REPLACE(tmp_xml, '</' || top_el || '>(.*?)$', hxml || '</' || top_el || E'>\\1'); END IF; IF ('bre.unapi' = ANY (includes)) THEN output := REGEXP_REPLACE( tmp_xml, '</' || top_el || '>(.*?)', XMLELEMENT( name abbr, XMLATTRIBUTES( 'http://www.w3.org/1999/xhtml' AS xmlns, 'unapi-id' AS class, 'tag:open-ils.org:U2@bre/' || obj_id || '/' || org AS title ) )::TEXT || '</' || top_el || E'>\\1' ); ELSE output := tmp_xml; END IF; IF ('bre.extern' = ANY (includes)) THEN output := REGEXP_REPLACE( tmp_xml, '</' || top_el || '>(.*?)', XMLELEMENT( name extern, XMLATTRIBUTES( 'http://open-ils.org/spec/biblio/v1' AS xmlns, me.creator AS creator, me.editor AS editor, me.create_date AS create_date, me.edit_date AS edit_date, me.quality AS quality, me.fingerprint AS fingerprint, me.tcn_source AS tcn_source, me.tcn_value AS tcn_value, me.owner AS owner, me.share_depth AS share_depth, me.active AS active, me.deleted AS deleted ) )::TEXT || '</' || top_el || E'>\\1' ); ELSE output := tmp_xml; END IF; output := REGEXP_REPLACE(output::TEXT,E'>\\s+<','><','gs')::XML; RETURN output; END;
Function: unapi.cbs(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
Returns: xml
Language: SQL
SELECT XMLELEMENT( name bib_source, XMLATTRIBUTES( NULL AS xmlns, -- TODO needs equivalent to http://open-ils.org/spec/holdings/v1 id AS ident, quality, transcendant, can_have_copies ), source ) FROM config.bib_source WHERE id = $1;
Function: unapi.ccs(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
Returns: xml
Language: SQL
SELECT XMLELEMENT( name status, XMLATTRIBUTES( CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns, id AS ident, holdable, opac_visible ), name ) FROM config.copy_status WHERE id = $1;
Function: unapi.circ(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
Returns: xml
Language: SQL
SELECT XMLELEMENT( name circ, XMLATTRIBUTES( CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns, 'tag:open-ils.org:U2@circ/' || id AS id, xact_start, due_date ), CASE WHEN ('aou' = ANY ($4)) THEN unapi.aou( circ_lib, $2, 'circ_lib', array_remove($4,'circ'), $5, $6, $7, $8, FALSE) ELSE NULL END, CASE WHEN ('acp' = ANY ($4)) THEN unapi.acp( circ_lib, $2, 'target_copy', array_remove($4,'circ'), $5, $6, $7, $8, FALSE) ELSE NULL END ) FROM action.circulation WHERE id = $1;
Function: unapi.holdings_xml(pref_lib bigint, include_xmlns integer, soffset text, slimit integer, includes text[], depth public.hstore, org public.hstore, ouid boolean, bid integer)
Returns: xml
Language: SQL
SELECT XMLELEMENT( name holdings, XMLATTRIBUTES( CASE WHEN $8 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns, CASE WHEN ('bre' = ANY ($5)) THEN 'tag:open-ils.org:U2@bre/' || $1 || '/' || $3 ELSE NULL END AS id, (SELECT record_has_holdable_copy FROM asset.record_has_holdable_copy($1)) AS has_holdable ), XMLELEMENT( name counts, (SELECT XMLAGG(XMLELEMENT::XML) FROM ( SELECT XMLELEMENT( name count, XMLATTRIBUTES('public' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow) )::text FROM asset.opac_ou_record_copy_count($2, $1) UNION SELECT XMLELEMENT( name count, XMLATTRIBUTES('staff' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow) )::text FROM asset.staff_ou_record_copy_count($2, $1) UNION SELECT XMLELEMENT( name count, XMLATTRIBUTES('pref_lib' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow) )::text FROM asset.opac_ou_record_copy_count($9, $1) ORDER BY 1 )x) ), CASE WHEN ('bmp' = ANY ($5)) THEN XMLELEMENT( name monograph_parts, (SELECT XMLAGG(bmp) FROM ( SELECT unapi.bmp( id, 'xml', 'monograph_part', array_remove( array_remove($5,'bre'), 'holdings_xml'), $3, $4, $6, $7, FALSE) FROM biblio.monograph_part WHERE NOT deleted AND record = $1 )x) ) ELSE NULL END, XMLELEMENT( name volumes, (SELECT XMLAGG(acn ORDER BY rank, name, label_sortkey) FROM ( -- Physical copies SELECT unapi.acn(y.id,'xml','volume',array_remove( array_remove($5,'holdings_xml'),'bre'), $3, $4, $6, $7, FALSE), y.rank, name, label_sortkey FROM evergreen.ranked_volumes($1, $2, $4, $6, $7, $9, $5) AS y UNION ALL -- Located URIs SELECT unapi.acn(uris.id,'xml','volume',array_remove( array_remove($5,'holdings_xml'),'bre'), $3, $4, $6, $7, FALSE), uris.rank, name, label_sortkey FROM evergreen.located_uris($1, $2, $9) AS uris )x) ), CASE WHEN ('ssub' = ANY ($5)) THEN XMLELEMENT( name subscriptions, (SELECT XMLAGG(ssub) FROM ( SELECT unapi.ssub(id,'xml','subscription','{}'::TEXT[], $3, $4, $6, $7, FALSE) FROM serial.subscription WHERE record_entry = $1 )x) ) ELSE NULL END, CASE WHEN ('acp' = ANY ($5)) THEN XMLELEMENT( name foreign_copies, (SELECT XMLAGG(acp) FROM ( SELECT unapi.acp(p.target_copy,'xml','copy',array_remove($5,'acp'), $3, $4, $6, $7, FALSE) FROM biblio.peer_bib_copy_map p JOIN asset.copy c ON (p.target_copy = c.id) WHERE NOT c.deleted AND p.peer_record = $1 LIMIT ($6 -> 'acp')::INT OFFSET ($7 -> 'acp')::INT )x) ) ELSE NULL END );
Function: unapi.memoize(include_xmlns text, soffset bigint, slimit text, depth text, org text[], includes text, ename integer, format public.hstore, obj_id public.hstore, classname boolean)
Returns: xml
Language: PLPGSQL
DECLARE key TEXT; output XML; BEGIN key := 'id' || COALESCE(obj_id::TEXT,'') || 'format' || COALESCE(format::TEXT,'') || 'ename' || COALESCE(ename::TEXT,'') || 'includes' || COALESCE(includes::TEXT,'{}'::TEXT[]::TEXT) || 'org' || COALESCE(org::TEXT,'') || 'depth' || COALESCE(depth::TEXT,'') || 'slimit' || COALESCE(slimit::TEXT,'') || 'soffset' || COALESCE(soffset::TEXT,'') || 'include_xmlns' || COALESCE(include_xmlns::TEXT,''); -- RAISE NOTICE 'memoize key: %', key; key := MD5(key); -- RAISE NOTICE 'memoize hash: %', key; -- XXX cache logic ... memcached? table? EXECUTE $$SELECT unapi.$$ || classname || $$( $1, $2, $3, $4, $5, $6, $7, $8, $9);$$ INTO output USING obj_id, format, ename, includes, org, depth, slimit, soffset, include_xmlns; RETURN output; END;
Function: unapi.metabib_virtual_record_feed(pref_lib bigint[], header_xml text, unapi_url text[], update_ts text, creator integer, description public.hstore, title public.hstore, include_xmlns boolean, soffset text, slimit text, depth text, org text, includes text, format xml, id_list integer)
Returns: xml
Language: PLPGSQL
DECLARE layout unapi.bre_output_layout%ROWTYPE; transform config.xml_transform%ROWTYPE; item_format TEXT; tmp_xml TEXT; xmlns_uri TEXT := 'http://open-ils.org/spec/feed-xml/v1'; ouid INT; element_list TEXT[]; BEGIN IF org = '-' OR org IS NULL THEN SELECT shortname INTO org FROM evergreen.org_top(); END IF; SELECT id INTO ouid FROM actor.org_unit WHERE shortname = org; SELECT * INTO layout FROM unapi.bre_output_layout WHERE name = format; IF layout.name IS NULL THEN RETURN NULL::XML; END IF; SELECT * INTO transform FROM config.xml_transform WHERE name = layout.transform; xmlns_uri := COALESCE(transform.namespace_uri,xmlns_uri); -- Gather the bib xml SELECT XMLAGG( unapi.mmr(i, format, '', includes, org, depth, slimit, soffset, include_xmlns, pref_lib)) INTO tmp_xml FROM UNNEST( id_list ) i; IF layout.title_element IS NOT NULL THEN EXECUTE 'SELECT XMLCONCAT( XMLELEMENT( name '|| layout.title_element ||', XMLATTRIBUTES( $1 AS xmlns), $3), $2)' INTO tmp_xml USING xmlns_uri, tmp_xml::XML, title; END IF; IF layout.description_element IS NOT NULL THEN EXECUTE 'SELECT XMLCONCAT( XMLELEMENT( name '|| layout.description_element ||', XMLATTRIBUTES( $1 AS xmlns), $3), $2)' INTO tmp_xml USING xmlns_uri, tmp_xml::XML, description; END IF; IF layout.creator_element IS NOT NULL THEN EXECUTE 'SELECT XMLCONCAT( XMLELEMENT( name '|| layout.creator_element ||', XMLATTRIBUTES( $1 AS xmlns), $3), $2)' INTO tmp_xml USING xmlns_uri, tmp_xml::XML, creator; END IF; IF layout.update_ts_element IS NOT NULL THEN EXECUTE 'SELECT XMLCONCAT( XMLELEMENT( name '|| layout.update_ts_element ||', XMLATTRIBUTES( $1 AS xmlns), $3), $2)' INTO tmp_xml USING xmlns_uri, tmp_xml::XML, update_ts; END IF; IF unapi_url IS NOT NULL THEN EXECUTE $$SELECT XMLCONCAT( XMLELEMENT( name link, XMLATTRIBUTES( 'http://www.w3.org/1999/xhtml' AS xmlns, 'unapi-server' AS rel, $1 AS href, 'unapi' AS title)), $2)$$ INTO tmp_xml USING unapi_url, tmp_xml::XML; END IF; IF header_xml IS NOT NULL THEN tmp_xml := XMLCONCAT(header_xml,tmp_xml::XML); END IF; element_list := regexp_split_to_array(layout.feed_top,E'\\.'); FOR i IN REVERSE ARRAY_UPPER(element_list, 1) .. 1 LOOP EXECUTE 'SELECT XMLELEMENT( name '|| quote_ident(element_list[i]) ||', XMLATTRIBUTES( $1 AS xmlns), $2)' INTO tmp_xml USING xmlns_uri, tmp_xml::XML; END LOOP; RETURN tmp_xml::XML; END;
Function: unapi.mmr(pref_lib bigint, include_xmlns text, soffset text, slimit text[], depth text, org integer, includes public.hstore, ename public.hstore, format boolean, obj_id integer)
Returns: xml
Language: PLPGSQL
DECLARE mmrec metabib.metarecord%ROWTYPE; leadrec biblio.record_entry%ROWTYPE; subrec biblio.record_entry%ROWTYPE; layout unapi.bre_output_layout%ROWTYPE; xfrm config.xml_transform%ROWTYPE; ouid INT; xml_buf TEXT; -- growing XML document tmp_xml TEXT; -- single-use XML string xml_frag TEXT; -- single-use XML fragment top_el TEXT; output XML; hxml XML; axml XML; subxml XML; -- subordinate records elements sub_xpath TEXT; parts TEXT[]; BEGIN -- xpath for extracting bre.marc values from subordinate records -- so they may be appended to the MARC of the master record prior -- to XSLT processing. -- subjects, isbn, issn, upc -- anything else? sub_xpath := '//*[starts-with(@tag, "6") or @tag="020" or @tag="022" or @tag="024"]'; IF org = '-' OR org IS NULL THEN SELECT shortname INTO org FROM evergreen.org_top(); END IF; SELECT id INTO ouid FROM actor.org_unit WHERE shortname = org; IF ouid IS NULL THEN RETURN NULL::XML; END IF; SELECT INTO mmrec * FROM metabib.metarecord WHERE id = obj_id; IF NOT FOUND THEN RETURN NULL::XML; END IF; -- TODO: aggregate holdings from constituent records IF format = 'holdings_xml' THEN -- the special case output := unapi.mmr_holdings_xml( obj_id, ouid, org, depth, array_remove(includes,'holdings_xml'), slimit, soffset, include_xmlns, pref_lib); RETURN output; END IF; SELECT * INTO layout FROM unapi.bre_output_layout WHERE name = format; IF layout.name IS NULL THEN RETURN NULL::XML; END IF; SELECT * INTO xfrm FROM config.xml_transform WHERE name = layout.transform; SELECT INTO leadrec * FROM biblio.record_entry WHERE id = mmrec.master_record; -- Grab distinct MVF for all records if requested IF ('mra' = ANY (includes)) THEN axml := unapi.mmr_mra(obj_id,NULL,NULL,NULL,org,depth,NULL,NULL,TRUE,pref_lib); ELSE axml := NULL::XML; END IF; xml_buf = leadrec.marc; hxml := NULL::XML; IF ('holdings_xml' = ANY (includes)) THEN hxml := unapi.mmr_holdings_xml( obj_id, ouid, org, depth, array_remove(includes,'holdings_xml'), slimit, soffset, include_xmlns, pref_lib); END IF; subxml := NULL::XML; parts := '{}'::TEXT[]; FOR subrec IN SELECT bre.* FROM biblio.record_entry bre JOIN metabib.metarecord_source_map mmsm ON (mmsm.source = bre.id) JOIN metabib.metarecord mmr ON (mmr.id = mmsm.metarecord) WHERE mmr.id = obj_id AND NOT bre.deleted ORDER BY CASE WHEN bre.id = mmr.master_record THEN 0 ELSE bre.id END LIMIT COALESCE((slimit->'bre')::INT, 5) LOOP IF subrec.id = leadrec.id THEN CONTINUE; END IF; -- Append choice data from the the non-lead records to the -- the lead record document parts := parts || xpath(sub_xpath, subrec.marc::XML)::TEXT[]; END LOOP; SELECT STRING_AGG( DISTINCT p , '' )::XML INTO subxml FROM UNNEST(parts) p; -- append data from the subordinate records to the -- main record document before applying the XSLT IF subxml IS NOT NULL THEN xml_buf := REGEXP_REPLACE(xml_buf, '</record>(.*?)$', subxml || '</record>' || E'\\1'); END IF; IF format = 'marcxml' THEN -- If we're not using the prefixed namespace in -- this record, then remove all declarations of it IF xml_buf !~ E'<marc:' THEN xml_buf := REGEXP_REPLACE(xml_buf, ' xmlns:marc="http://www.loc.gov/MARC21/slim"', '', 'g'); END IF; ELSE xml_buf := oils_xslt_process(xml_buf, xfrm.xslt)::XML; END IF; -- update top_el to reflect the change in xml_buf, which may -- now be a different type of document (e.g. record -> mods) top_el := REGEXP_REPLACE(xml_buf, E'^.*?<((?:\\S+:)?' || layout.holdings_element || ').*$', E'\\1'); IF axml IS NOT NULL THEN xml_buf := REGEXP_REPLACE(xml_buf, '</' || top_el || '>(.*?)$', axml || '</' || top_el || E'>\\1'); END IF; IF hxml IS NOT NULL THEN xml_buf := REGEXP_REPLACE(xml_buf, '</' || top_el || '>(.*?)$', hxml || '</' || top_el || E'>\\1'); END IF; IF ('mmr.unapi' = ANY (includes)) THEN output := REGEXP_REPLACE( xml_buf, '</' || top_el || '>(.*?)', XMLELEMENT( name abbr, XMLATTRIBUTES( 'http://www.w3.org/1999/xhtml' AS xmlns, 'unapi-id' AS class, 'tag:open-ils.org:U2@mmr/' || obj_id || '/' || org AS title ) )::TEXT || '</' || top_el || E'>\\1' ); ELSE output := xml_buf; END IF; -- remove ignorable whitesace output := REGEXP_REPLACE(output::TEXT,E'>\\s+<','><','gs')::XML; RETURN output; END;
Function: unapi.mmr_holdings_xml(pref_lib bigint, include_xmlns integer, soffset text, slimit integer, includes text[], depth public.hstore, org public.hstore, ouid boolean, mid integer)
Returns: xml
Language: SQL
SELECT XMLELEMENT( name holdings, XMLATTRIBUTES( CASE WHEN $8 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns, CASE WHEN ('mmr' = ANY ($5)) THEN 'tag:open-ils.org:U2@mmr/' || $1 || '/' || $3 ELSE NULL END AS id, (SELECT metarecord_has_holdable_copy FROM asset.metarecord_has_holdable_copy($1)) AS has_holdable ), XMLELEMENT( name counts, (SELECT XMLAGG(XMLELEMENT::XML) FROM ( SELECT XMLELEMENT( name count, XMLATTRIBUTES('public' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow) )::text FROM asset.opac_ou_metarecord_copy_count($2, $1) UNION SELECT XMLELEMENT( name count, XMLATTRIBUTES('staff' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow) )::text FROM asset.staff_ou_metarecord_copy_count($2, $1) UNION SELECT XMLELEMENT( name count, XMLATTRIBUTES('pref_lib' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow) )::text FROM asset.opac_ou_metarecord_copy_count($9, $1) ORDER BY 1 )x) ), -- XXX monograph_parts and foreign_copies are skipped in MRs ... put them back some day? XMLELEMENT( name volumes, (SELECT XMLAGG(acn ORDER BY rank, name, label_sortkey) FROM ( -- Physical copies SELECT unapi.acn(y.id,'xml','volume',array_remove( array_remove($5,'holdings_xml'),'bre'), $3, $4, $6, $7, FALSE), y.rank, name, label_sortkey FROM evergreen.ranked_volumes((SELECT ARRAY_AGG(source) FROM metabib.metarecord_source_map WHERE metarecord = $1), $2, $4, $6, $7, $9, $5) AS y UNION ALL -- Located URIs SELECT unapi.acn(uris.id,'xml','volume',array_remove( array_remove($5,'holdings_xml'),'bre'), $3, $4, $6, $7, FALSE), uris.rank, name, label_sortkey FROM evergreen.located_uris((SELECT ARRAY_AGG(source) FROM metabib.metarecord_source_map WHERE metarecord = $1), $2, $9) AS uris )x) ), CASE WHEN ('ssub' = ANY ($5)) THEN XMLELEMENT( name subscriptions, (SELECT XMLAGG(ssub) FROM ( SELECT unapi.ssub(id,'xml','subscription','{}'::TEXT[], $3, $4, $6, $7, FALSE) FROM serial.subscription WHERE record_entry IN (SELECT source FROM metabib.metarecord_source_map WHERE metarecord = $1) )x) ) ELSE NULL END );
Function: unapi.mmr_mra(pref_lib bigint, include_xmlns text, soffset text, slimit text[], depth text, org integer, includes public.hstore, ename public.hstore, format boolean, obj_id integer)
Returns: xml
Language: SQL
SELECT XMLELEMENT( name attributes, XMLATTRIBUTES( CASE WHEN $9 THEN 'http://open-ils.org/spec/indexing/v1' ELSE NULL END AS xmlns, 'tag:open-ils.org:U2@mmr/' || $1 AS metarecord ), (SELECT XMLAGG(foo.y) FROM ( WITH sourcelist AS ( WITH aou AS (SELECT COALESCE(id, (evergreen.org_top()).id) AS id FROM actor.org_unit WHERE shortname = $5 LIMIT 1), basevm AS (SELECT c_attrs FROM asset.patron_default_visibility_mask()), circvm AS (SELECT search.calculate_visibility_attribute_test('circ_lib', ARRAY_AGG(aoud.id)) AS mask FROM aou, LATERAL actor.org_unit_descendants(aou.id, $6) aoud) SELECT source FROM aou, circvm, basevm, metabib.metarecord_source_map mmsm WHERE mmsm.metarecord = $1 AND ( EXISTS ( SELECT 1 FROM circvm, basevm, asset.copy_vis_attr_cache acvac WHERE acvac.vis_attr_vector @@ (basevm.c_attrs || '&' || circvm.mask)::query_int AND acvac.record = mmsm.source ) OR EXISTS (SELECT 1 FROM evergreen.located_uris(source, aou.id, $10) LIMIT 1) OR EXISTS (SELECT 1 FROM biblio.record_entry b JOIN config.bib_source src ON (b.source = src.id) WHERE src.transcendant AND b.id = mmsm.source) ) ) SELECT cmra.aid, XMLELEMENT( name field, XMLATTRIBUTES( cmra.attr AS name, cmra.value AS "coded-value", cmra.aid AS "cvmid", rad.composite, rad.multi, rad.filter, rad.sorter, cmra.source_list ), cmra.value ) FROM ( SELECT DISTINCT aid, attr, value, STRING_AGG(x.id::TEXT, ',') AS source_list FROM ( SELECT v.source AS id, c.id AS aid, c.ctype AS attr, c.code AS value FROM metabib.record_attr_vector_list v JOIN config.coded_value_map c ON ( c.id = ANY( v.vlist ) ) ) AS x JOIN sourcelist ON (x.id = sourcelist.source) GROUP BY 1, 2, 3 ) AS cmra JOIN config.record_attr_definition rad ON (cmra.attr = rad.name) UNION ALL SELECT umra.aid, XMLELEMENT( name field, XMLATTRIBUTES( umra.attr AS name, rad.composite, rad.multi, rad.filter, rad.sorter ), umra.value ) FROM ( SELECT DISTINCT aid, attr, value FROM ( SELECT v.source AS id, m.id AS aid, m.attr AS attr, m.value AS value FROM metabib.record_attr_vector_list v JOIN metabib.uncontrolled_record_attr_value m ON ( m.id = ANY( v.vlist ) ) ) AS x JOIN sourcelist ON (x.id = sourcelist.source) ) AS umra JOIN config.record_attr_definition rad ON (umra.attr = rad.name) ORDER BY 1 )foo(id,y) ) )
Function: unapi.mra(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
Returns: xml
Language: SQL
SELECT XMLELEMENT( name attributes, XMLATTRIBUTES( CASE WHEN $9 THEN 'http://open-ils.org/spec/indexing/v1' ELSE NULL END AS xmlns, 'tag:open-ils.org:U2@mra/' || $1 AS id, 'tag:open-ils.org:U2@bre/' || $1 AS record ), (SELECT XMLAGG(foo.y) FROM ( SELECT XMLELEMENT( name field, XMLATTRIBUTES( mra.attr AS name, cvm.value AS "coded-value", cvm.id AS "cvmid", rad.composite, rad.multi, rad.filter, rad.sorter ), mra.value ) FROM metabib.record_attr_flat mra JOIN config.record_attr_definition rad ON (mra.attr = rad.name) LEFT JOIN config.coded_value_map cvm ON (cvm.ctype = mra.attr AND code = mra.value) WHERE mra.id = $1 )foo(y) ) )
Function: unapi.sbsum(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
Returns: xml
Language: SQL
SELECT XMLELEMENT( name serial_summary, XMLATTRIBUTES( CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns, 'tag:open-ils.org:U2@sbsum/' || id AS id, 'sbsum' AS type, generated_coverage, textual_holdings, show_generated ), CASE WHEN ('sdist' = ANY ($4)) THEN unapi.sdist( distribution, 'xml', 'distribtion', array_remove($4,'ssum'), $5, $6, $7, $8, FALSE) ELSE NULL END ) FROM serial.basic_summary ssum WHERE id = $1 GROUP BY id, generated_coverage, textual_holdings, distribution, show_generated;
Function: unapi.sdist(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
Returns: xml
Language: SQL
SELECT XMLELEMENT( name distribution, XMLATTRIBUTES( CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns, 'tag:open-ils.org:U2@sdist/' || id AS id, 'tag:open-ils.org:U2@acn/' || receive_call_number AS receive_call_number, 'tag:open-ils.org:U2@acn/' || bind_call_number AS bind_call_number, unit_label_prefix, label, unit_label_suffix, summary_method ), unapi.aou( holding_lib, $2, 'holding_lib', array_remove($4,'sdist'), $5, $6, $7, $8), CASE WHEN subscription IS NOT NULL AND ('ssub' = ANY ($4)) THEN unapi.ssub( subscription, 'xml', 'subscription', array_remove($4,'sdist'), $5, $6, $7, $8, FALSE) ELSE NULL END, CASE WHEN ('sstr' = ANY ($4)) THEN XMLELEMENT( name streams, (SELECT XMLAGG(sstr) FROM ( SELECT unapi.sstr( id, 'xml', 'stream', array_remove($4,'sdist'), $5, $6, $7, $8, FALSE) FROM serial.stream WHERE distribution = sdist.id )x) ) ELSE NULL END, XMLELEMENT( name summaries, CASE WHEN ('sbsum' = ANY ($4)) THEN (SELECT XMLAGG(sbsum) FROM ( SELECT unapi.sbsum( id, 'xml', 'serial_summary', array_remove($4,'sdist'), $5, $6, $7, $8, FALSE) FROM serial.basic_summary WHERE distribution = sdist.id )x) ELSE NULL END, CASE WHEN ('sisum' = ANY ($4)) THEN (SELECT XMLAGG(sisum) FROM ( SELECT unapi.sisum( id, 'xml', 'serial_summary', array_remove($4,'sdist'), $5, $6, $7, $8, FALSE) FROM serial.index_summary WHERE distribution = sdist.id )x) ELSE NULL END, CASE WHEN ('sssum' = ANY ($4)) THEN (SELECT XMLAGG(sssum) FROM ( SELECT unapi.sssum( id, 'xml', 'serial_summary', array_remove($4,'sdist'), $5, $6, $7, $8, FALSE) FROM serial.supplement_summary WHERE distribution = sdist.id )x) ELSE NULL END ) ) FROM serial.distribution sdist WHERE id = $1 GROUP BY id, label, unit_label_prefix, unit_label_suffix, holding_lib, summary_method, subscription, receive_call_number, bind_call_number;
Function: unapi.siss(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
Returns: xml
Language: SQL
SELECT XMLELEMENT( name issuance, XMLATTRIBUTES( CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns, 'tag:open-ils.org:U2@siss/' || id AS id, create_date, edit_date, label, date_published, holding_code, holding_type, holding_link_id ), CASE WHEN subscription IS NOT NULL AND ('ssub' = ANY ($4)) THEN unapi.ssub( subscription, 'xml', 'subscription', array_remove($4,'siss'), $5, $6, $7, $8, FALSE) ELSE NULL END, CASE WHEN ('sitem' = ANY ($4)) THEN XMLELEMENT( name items, (SELECT XMLAGG(sitem) FROM ( SELECT unapi.sitem( id, 'xml', 'serial_item', array_remove($4,'siss'), $5, $6, $7, $8, FALSE) FROM serial.item WHERE issuance = sstr.id )x) ) ELSE NULL END ) FROM serial.issuance sstr WHERE id = $1 GROUP BY id, create_date, edit_date, label, date_published, holding_code, holding_type, holding_link_id, subscription;
Function: unapi.sisum(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
Returns: xml
Language: SQL
SELECT XMLELEMENT( name serial_summary, XMLATTRIBUTES( CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns, 'tag:open-ils.org:U2@sbsum/' || id AS id, 'sisum' AS type, generated_coverage, textual_holdings, show_generated ), CASE WHEN ('sdist' = ANY ($4)) THEN unapi.sdist( distribution, 'xml', 'distribtion', array_remove($4,'ssum'), $5, $6, $7, $8, FALSE) ELSE NULL END ) FROM serial.index_summary ssum WHERE id = $1 GROUP BY id, generated_coverage, textual_holdings, distribution, show_generated;
Function: unapi.sitem(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
Returns: xml
Language: SQL
SELECT XMLELEMENT( name serial_item, XMLATTRIBUTES( CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns, 'tag:open-ils.org:U2@sitem/' || id AS id, 'tag:open-ils.org:U2@siss/' || issuance AS issuance, date_expected, date_received ), CASE WHEN issuance IS NOT NULL AND ('siss' = ANY ($4)) THEN unapi.siss( issuance, $2, 'issuance', array_remove($4,'sitem'), $5, $6, $7, $8, FALSE) ELSE NULL END, CASE WHEN stream IS NOT NULL AND ('sstr' = ANY ($4)) THEN unapi.sstr( stream, $2, 'stream', array_remove($4,'sitem'), $5, $6, $7, $8, FALSE) ELSE NULL END, CASE WHEN unit IS NOT NULL AND ('sunit' = ANY ($4)) THEN unapi.sunit( unit, $2, 'serial_unit', array_remove($4,'sitem'), $5, $6, $7, $8, FALSE) ELSE NULL END, CASE WHEN uri IS NOT NULL AND ('auri' = ANY ($4)) THEN unapi.auri( uri, $2, 'uri', array_remove($4,'sitem'), $5, $6, $7, $8, FALSE) ELSE NULL END -- XMLELEMENT( name notes, -- CASE -- WHEN ('acpn' = ANY ($4)) THEN -- (SELECT XMLAGG(acpn) FROM ( -- SELECT unapi.acpn( id, 'xml', 'copy_note', array_remove($4,'acp'), $5, $6, $7, $8) -- FROM asset.copy_note -- WHERE owning_copy = cp.id AND pub -- )x) -- ELSE NULL -- END -- ) ) FROM serial.item sitem WHERE id = $1;
Function: unapi.sssum(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
Returns: xml
Language: SQL
SELECT XMLELEMENT( name serial_summary, XMLATTRIBUTES( CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns, 'tag:open-ils.org:U2@sbsum/' || id AS id, 'sssum' AS type, generated_coverage, textual_holdings, show_generated ), CASE WHEN ('sdist' = ANY ($4)) THEN unapi.sdist( distribution, 'xml', 'distribtion', array_remove($4,'ssum'), $5, $6, $7, $8, FALSE) ELSE NULL END ) FROM serial.supplement_summary ssum WHERE id = $1 GROUP BY id, generated_coverage, textual_holdings, distribution, show_generated;
Function: unapi.sstr(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
Returns: xml
Language: SQL
SELECT XMLELEMENT( name stream, XMLATTRIBUTES( CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns, 'tag:open-ils.org:U2@sstr/' || id AS id, routing_label ), CASE WHEN distribution IS NOT NULL AND ('sdist' = ANY ($4)) THEN unapi.sssum( distribution, 'xml', 'distribtion', array_remove($4,'sstr'), $5, $6, $7, $8, FALSE) ELSE NULL END, CASE WHEN ('sitem' = ANY ($4)) THEN XMLELEMENT( name items, (SELECT XMLAGG(sitem) FROM ( SELECT unapi.sitem( id, 'xml', 'serial_item', array_remove($4,'sstr'), $5, $6, $7, $8, FALSE) FROM serial.item WHERE stream = sstr.id )x) ) ELSE NULL END ) FROM serial.stream sstr WHERE id = $1 GROUP BY id, routing_label, distribution;
Function: unapi.ssub(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
Returns: xml
Language: SQL
SELECT XMLELEMENT( name subscription, XMLATTRIBUTES( CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns, 'tag:open-ils.org:U2@ssub/' || id AS id, 'tag:open-ils.org:U2@aou/' || owning_lib AS owning_lib, start_date AS start, end_date AS end, expected_date_offset ), CASE WHEN ('sdist' = ANY ($4)) THEN XMLELEMENT( name distributions, (SELECT XMLAGG(sdist) FROM ( SELECT unapi.sdist( id, 'xml', 'distribution', array_remove($4,'ssub'), $5, $6, $7, $8, FALSE) FROM serial.distribution WHERE subscription = ssub.id )x) ) ELSE NULL END ) FROM serial.subscription ssub WHERE id = $1 GROUP BY id, start_date, end_date, expected_date_offset, owning_lib;
Function: unapi.sunit(include_xmlns bigint, soffset text, slimit text, depth text[], org text, includes integer, ename public.hstore, format public.hstore, obj_id boolean)
Returns: xml
Language: SQL
SELECT XMLELEMENT( name serial_unit, XMLATTRIBUTES( CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns, 'tag:open-ils.org:U2@acp/' || id AS id, id AS copy_id, create_date, edit_date, copy_number, circulate, deposit, ref, holdable, deleted, deposit_amount, price, barcode, circ_modifier, circ_as_type, opac_visible, age_protect, status_changed_time, floating, mint_condition, detailed_contents, sort_key, summary_contents, cost ), unapi.ccs( status, $2, 'status', array_remove( array_remove($4,'acp'),'sunit'), $5, $6, $7, $8, FALSE), unapi.acl( location, $2, 'location', array_remove( array_remove($4,'acp'),'sunit'), $5, $6, $7, $8, FALSE), unapi.aou( circ_lib, $2, 'circ_lib', array_remove( array_remove($4,'acp'),'sunit'), $5, $6, $7, $8), unapi.aou( circ_lib, $2, 'circlib', array_remove( array_remove($4,'acp'),'sunit'), $5, $6, $7, $8), CASE WHEN ('acn' = ANY ($4)) THEN unapi.acn( call_number, $2, 'call_number', array_remove($4,'acp'), $5, $6, $7, $8, FALSE) ELSE NULL END, XMLELEMENT( name copy_notes, CASE WHEN ('acpn' = ANY ($4)) THEN (SELECT XMLAGG(acpn) FROM ( SELECT unapi.acpn( id, 'xml', 'copy_note', array_remove( array_remove($4,'acp'),'sunit'), $5, $6, $7, $8, FALSE) FROM asset.copy_note WHERE owning_copy = cp.id AND pub )x) ELSE NULL END ), XMLELEMENT( name statcats, CASE WHEN ('ascecm' = ANY ($4)) THEN (SELECT XMLAGG(ascecm) FROM ( SELECT unapi.ascecm( stat_cat_entry, 'xml', 'statcat', array_remove($4,'acp'), $5, $6, $7, $8, FALSE) FROM asset.stat_cat_entry_copy_map WHERE owning_copy = cp.id )x) ELSE NULL END ), XMLELEMENT( name foreign_records, CASE WHEN ('bre' = ANY ($4)) THEN (SELECT XMLAGG(bre) FROM ( SELECT unapi.bre(peer_record,'marcxml','record','{}'::TEXT[], $5, $6, $7, $8, FALSE) FROM biblio.peer_bib_copy_map WHERE target_copy = cp.id )x) ELSE NULL END ), CASE WHEN ('bmp' = ANY ($4)) THEN XMLELEMENT( name monograph_parts, (SELECT XMLAGG(bmp) FROM ( SELECT unapi.bmp( part, 'xml', 'monograph_part', array_remove($4,'acp'), $5, $6, $7, $8, FALSE) FROM asset.copy_part_map WHERE target_copy = cp.id )x) ) ELSE NULL END, CASE WHEN ('circ' = ANY ($4)) THEN XMLELEMENT( name current_circulation, (SELECT XMLAGG(circ) FROM ( SELECT unapi.circ( id, 'xml', 'circ', array_remove($4,'circ'), $5, $6, $7, $8, FALSE) FROM action.circulation WHERE target_copy = cp.id AND checkin_time IS NULL )x) ) ELSE NULL END ) FROM serial.unit cp WHERE id = $1 AND cp.deleted IS FALSE GROUP BY id, status, location, circ_lib, call_number, create_date, edit_date, copy_number, circulate, floating, mint_condition, deposit, ref, holdable, deleted, deposit_amount, price, barcode, circ_modifier, circ_as_type, opac_visible, status_changed_time, detailed_contents, sort_key, summary_contents, cost, age_protect;
Schema url_verify
Table: url_verify.session
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE#1 NOT NULL | |
actor.org_unit.id | owning_lib | integer | UNIQUE#1 NOT NULL |
actor.usr.id | creator | integer | NOT NULL |
container.biblio_record_entry_bucket.id | container | integer | NOT NULL |
create_time | timestamp with time zone | NOT NULL DEFAULT now() | |
search | text | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: url_verify.url
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
url_verify.url.id | redirect_from | integer | |
container.biblio_record_entry_bucket_item.id | item | integer | |
url_verify.session.id | session | integer | |
url_verify.url_selector.id | url_selector | integer | |
tag | text | ||
subfield | text | ||
ord | integer | ||
full_url | text | NOT NULL | |
scheme | text | ||
username | text | ||
password | text | ||
host | text | ||
domain | text | ||
tld | text | ||
port | text | ||
path | text | ||
page | text | ||
query | text | ||
fragment | text |
Name | Constraint |
---|---|
redirect_or_from_item | CHECK (((redirect_from IS NOT NULL) OR ((item IS NOT NULL) AND (url_selector IS NOT NULL) AND (tag IS NOT NULL) AND (subfield IS NOT NULL) AND (ord IS NOT NULL)))) |
Tables referencing this one via Foreign Key Constraints:
Table: url_verify.url_selector
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
xpath | text | UNIQUE#1 NOT NULL | |
url_verify.session.id | session | integer | UNIQUE#1 NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: url_verify.url_verification
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
url_verify.url.id | url | integer | NOT NULL |
url_verify.verification_attempt.id | attempt | integer | NOT NULL |
req_time | timestamp with time zone | NOT NULL DEFAULT now() | |
res_time | timestamp with time zone | ||
res_code | integer | ||
res_text | text | ||
url_verify.url.id | redirect_to | integer |
Name | Constraint |
---|---|
url_verification_res_code_check | CHECK (((res_code >= 100) AND (res_code <= 999))) |
Table: url_verify.verification_attempt
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.usr.id | usr | integer | NOT NULL |
url_verify.session.id | session | integer | NOT NULL |
start_time | timestamp with time zone | NOT NULL DEFAULT now() | |
finish_time | timestamp with time zone |
Tables referencing this one via Foreign Key Constraints:
Function: url_verify.extract_urls(item_id integer, session_id integer)
Returns: integer
Language: PLPGSQL
DECLARE last_seen_tag TEXT; current_tag TEXT; current_sf TEXT; current_url TEXT; current_ord INT; current_url_pos INT; current_selector url_verify.url_selector%ROWTYPE; BEGIN current_ord := 1; FOR current_selector IN SELECT * FROM url_verify.url_selector s WHERE s.session = session_id LOOP current_url_pos := 1; LOOP SELECT (oils_xpath(current_selector.xpath || '/text()', b.marc))[current_url_pos] INTO current_url FROM biblio.record_entry b JOIN container.biblio_record_entry_bucket_item c ON (c.target_biblio_record_entry = b.id) WHERE c.id = item_id; EXIT WHEN current_url IS NULL; SELECT (oils_xpath(current_selector.xpath || '/../@tag', b.marc))[current_url_pos] INTO current_tag FROM biblio.record_entry b JOIN container.biblio_record_entry_bucket_item c ON (c.target_biblio_record_entry = b.id) WHERE c.id = item_id; IF current_tag IS NULL THEN current_tag := last_seen_tag; ELSE last_seen_tag := current_tag; END IF; SELECT (oils_xpath(current_selector.xpath || '/@code', b.marc))[current_url_pos] INTO current_sf FROM biblio.record_entry b JOIN container.biblio_record_entry_bucket_item c ON (c.target_biblio_record_entry = b.id) WHERE c.id = item_id; INSERT INTO url_verify.url (session, item, url_selector, tag, subfield, ord, full_url) VALUES ( session_id, item_id, current_selector.id, current_tag, current_sf, current_ord, current_url); current_url_pos := current_url_pos + 1; current_ord := current_ord + 1; END LOOP; END LOOP; RETURN current_ord - 1; END;
Function: url_verify.ingest_url()
Returns: trigger
Language: PLPGSQL
DECLARE tmp_row url_verify.url%ROWTYPE; BEGIN SELECT * INTO tmp_row FROM url_verify.parse_url(NEW.full_url); NEW.scheme := tmp_row.scheme; NEW.username := tmp_row.username; NEW.password := tmp_row.password; NEW.host := tmp_row.host; NEW.domain := tmp_row.domain; NEW.tld := tmp_row.tld; NEW.port := tmp_row.port; NEW.path := tmp_row.path; NEW.page := tmp_row.page; NEW.query := tmp_row.query; NEW.fragment := tmp_row.fragment; RETURN NEW; END;
Function: url_verify.parse_url(url_in text)
Returns: url
Language: PLPERLU
use Rose::URI; my $url_in = shift; my $url = Rose::URI->new($url_in); my %parts = map { $_ => $url->$_ } qw/scheme username password host port path query fragment/; $parts{full_url} = $url_in; ($parts{domain} = $parts{host}) =~ s/^[^.]+\.//; ($parts{tld} = $parts{domain}) =~ s/(?:[^.]+\.)+//; ($parts{page} = $parts{path}) =~ s#(?:[^/]*/)+##; return \%parts;
Schema vandelay
Table: vandelay.authority_attr_definition
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
code | text | UNIQUE NOT NULL | |
description | text | ||
xpath | text | NOT NULL | |
remove | text | NOT NULL DEFAULT ''::text |
Tables referencing this one via Foreign Key Constraints:
Table: vandelay.authority_match
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
vandelay.queued_authority_record.id | queued_record | bigint | |
authority.record_entry.id | eg_record | bigint | |
quality | integer | NOT NULL | |
match_score | integer | NOT NULL |
Table: vandelay.authority_queue
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY DEFAULT nextval('vandelay.queue_id_seq'::regclass) | |
owner | integer | UNIQUE#1 NOT NULL | |
name | text | UNIQUE#1 NOT NULL | |
complete | boolean | NOT NULL DEFAULT false | |
match_set | integer | ||
queue_type | vandelay.authority_queue_queue_type | UNIQUE#1 NOT NULL DEFAULT 'authority'::vandelay.authority_queue_queue_type |
Table vandelay.authority_queue Inherits queue,
Tables referencing this one via Foreign Key Constraints:
Table: vandelay.bib_attr_definition
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
code | text | UNIQUE NOT NULL | |
description | text | ||
xpath | text | NOT NULL | |
remove | text | NOT NULL DEFAULT ''::text |
Tables referencing this one via Foreign Key Constraints:
Table: vandelay.bib_match
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
vandelay.queued_bib_record.id | queued_record | bigint | |
biblio.record_entry.id | eg_record | bigint | |
quality | integer | NOT NULL DEFAULT 1 | |
match_score | integer | NOT NULL |
Table: vandelay.bib_queue
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY DEFAULT nextval('vandelay.queue_id_seq'::regclass) | |
owner | integer | UNIQUE#1 NOT NULL | |
name | text | UNIQUE#1 NOT NULL | |
complete | boolean | NOT NULL DEFAULT false | |
match_set | integer | ||
queue_type | vandelay.bib_queue_queue_type | UNIQUE#1 NOT NULL DEFAULT 'bib'::vandelay.bib_queue_queue_type | |
vandelay.import_item_attr_definition.id | item_attr_def | bigint | |
container.biblio_record_entry_bucket.id | match_bucket | integer |
Table vandelay.bib_queue Inherits queue,
Tables referencing this one via Foreign Key Constraints:
Table: vandelay.import_bib_trash_fields
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
vandelay.import_bib_trash_group.id | grp | integer | UNIQUE#1 NOT NULL |
field | text | UNIQUE#1 NOT NULL |
Table: vandelay.import_bib_trash_group
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
actor.org_unit.id | owner | integer | UNIQUE#1 NOT NULL |
label | text | UNIQUE#1 NOT NULL | |
always_apply | boolean | NOT NULL DEFAULT false |
Tables referencing this one via Foreign Key Constraints:
Table: vandelay.import_error
F-Key | Name | Type | Description |
---|---|---|---|
code | text | PRIMARY KEY | |
description | text | NOT NULL |
Tables referencing this one via Foreign Key Constraints:
Table: vandelay.import_item
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
vandelay.queued_bib_record.id | record | bigint | NOT NULL |
vandelay.import_item_attr_definition.id | definition | bigint | NOT NULL |
vandelay.import_error.code | import_error | text | |
error_detail | text | ||
imported_as | bigint | ||
import_time | timestamp with time zone | ||
owning_lib | integer | ||
circ_lib | integer | ||
call_number | text | ||
copy_number | integer | ||
status | integer | ||
location | integer | ||
circulate | boolean | ||
deposit | boolean | ||
deposit_amount | numeric(8,2) | ||
ref | boolean | ||
holdable | boolean | ||
price | numeric(8,2) | ||
barcode | text | ||
circ_modifier | text | ||
circ_as_type | text | ||
alert_message | text | ||
pub_note | text | ||
priv_note | text | ||
stat_cat_data | text | ||
parts_data | text | ||
opac_visible | boolean | ||
internal_id | bigint |
Table: vandelay.import_item_attr_definition
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
actor.org_unit.id | owner | integer | UNIQUE#1 NOT NULL |
name | text | UNIQUE#1 NOT NULL | |
tag | text | NOT NULL | |
keep | boolean | NOT NULL DEFAULT false | |
owning_lib | text | ||
circ_lib | text | ||
call_number | text | ||
copy_number | text | ||
status | text | ||
location | text | ||
circulate | text | ||
deposit | text | ||
deposit_amount | text | ||
ref | text | ||
holdable | text | ||
price | text | ||
barcode | text | ||
circ_modifier | text | ||
circ_as_type | text | ||
alert_message | text | ||
opac_visible | text | ||
pub_note_title | text | ||
pub_note | text | ||
priv_note_title | text | ||
priv_note | text | ||
internal_id | text | ||
stat_cat_data | text | ||
parts_data | text |
Tables referencing this one via Foreign Key Constraints:
Table: vandelay.match_set
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
name | text | UNIQUE#1 NOT NULL | |
actor.org_unit.id | owner | integer | UNIQUE#1 NOT NULL |
mtype | text | UNIQUE#1 NOT NULL DEFAULT 'biblio'::text |
Tables referencing this one via Foreign Key Constraints:
Table: vandelay.match_set_point
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
vandelay.match_set.id | match_set | integer | |
vandelay.match_set_point.id | parent | integer | |
bool_op | text | ||
config.record_attr_definition.name | svf | text | |
tag | text | ||
subfield | text | ||
negate | boolean | DEFAULT false | |
quality | integer | NOT NULL DEFAULT 1 | |
heading | boolean | NOT NULL DEFAULT false |
Name | Constraint |
---|---|
match_set_point_bool_op_check | CHECK (((bool_op IS NULL) OR (bool_op = ANY (ARRAY['AND'::text, 'OR'::text, 'NOT'::text])))) |
vmsp_need_a_subfield_with_a_tag | CHECK ((((tag IS NOT NULL) AND (subfield IS NOT NULL)) OR (tag IS NULL))) |
vmsp_need_a_tag_or_a_ff_or_a_bo | CHECK ((((tag IS NOT NULL) AND (svf IS NULL) AND (heading IS FALSE) AND (bool_op IS NULL)) OR ((tag IS NULL) AND (svf IS NOT NULL) AND (heading IS FALSE) AND (bool_op IS NULL)) OR ((tag IS NULL) AND (svf IS NULL) AND (heading IS TRUE) AND (bool_op IS NULL)) OR ((tag IS NULL) AND (svf IS NULL) AND (heading IS FALSE) AND (bool_op IS NOT NULL)))) |
Tables referencing this one via Foreign Key Constraints:
Table: vandelay.match_set_quality
F-Key | Name | Type | Description |
---|---|---|---|
id | serial | PRIMARY KEY | |
vandelay.match_set.id | match_set | integer | NOT NULL |
config.record_attr_definition.name | svf | text | |
tag | text | ||
subfield | text | ||
value | text | NOT NULL | |
quality | integer | NOT NULL DEFAULT 1 |
Name | Constraint |
---|---|
vmsq_need_a_subfield_with_a_tag | CHECK ((((tag IS NOT NULL) AND (subfield IS NOT NULL)) OR (tag IS NULL))) |
vmsq_need_a_tag_or_a_ff | CHECK ((((tag IS NOT NULL) AND (svf IS NULL)) OR ((tag IS NULL) AND (svf IS NOT NULL)))) |
Table: vandelay.merge_profile
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
actor.org_unit.id | owner | integer | UNIQUE#1 NOT NULL |
name | text | UNIQUE#1 NOT NULL | |
add_spec | text | ||
replace_spec | text | ||
strip_spec | text | ||
preserve_spec | text | ||
update_bib_source | boolean | NOT NULL DEFAULT false | |
update_bib_editor | boolean | NOT NULL DEFAULT false | |
lwm_ratio | numeric |
Name | Constraint |
---|---|
add_replace_strip_or_preserve | CHECK (((preserve_spec IS NOT NULL) OR (replace_spec IS NOT NULL) OR ((preserve_spec IS NULL) AND (replace_spec IS NULL)))) |
Table: vandelay.queue
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
actor.usr.id | owner | integer | NOT NULL |
name | text | NOT NULL | |
complete | boolean | NOT NULL DEFAULT false | |
vandelay.match_set.id | match_set | integer |
Table: vandelay.queued_authority_record
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY DEFAULT nextval('vandelay.queued_record_id_seq'::regclass) | |
create_time | timestamp with time zone | NOT NULL DEFAULT now() | |
import_time | timestamp with time zone | ||
purpose | text | NOT NULL DEFAULT 'import'::text | |
marc | text | NOT NULL | |
quality | integer | NOT NULL | |
vandelay.authority_queue.id | queue | integer | NOT NULL |
authority.record_entry.id | imported_as | integer | |
vandelay.import_error.code | import_error | text | |
error_detail | text |
Table vandelay.queued_authority_record Inherits queued_record,
Name | Constraint |
---|---|
queued_record_purpose_check | CHECK ((purpose = ANY (ARRAY['import'::text, 'overlay'::text]))) |
Tables referencing this one via Foreign Key Constraints:
queued_authority_record_queue_idx queueTable: vandelay.queued_authority_record_attr
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
vandelay.queued_authority_record.id | record | bigint | NOT NULL |
vandelay.authority_attr_definition.id | field | integer | NOT NULL |
attr_value | text | NOT NULL |
Table: vandelay.queued_bib_record
F-Key | Name | Type | Description |
---|---|---|---|
id | bigint | PRIMARY KEY DEFAULT nextval('vandelay.queued_record_id_seq'::regclass) | |
create_time | timestamp with time zone | NOT NULL DEFAULT now() | |
import_time | timestamp with time zone | ||
purpose | text | NOT NULL DEFAULT 'import'::text | |
marc | text | NOT NULL | |
quality | integer | NOT NULL | |
vandelay.bib_queue.id | queue | integer | NOT NULL |
config.bib_source.id | bib_source | integer | |
biblio.record_entry.id | imported_as | bigint | |
vandelay.import_error.code | import_error | text | |
error_detail | text |
Table vandelay.queued_bib_record Inherits queued_record,
Name | Constraint |
---|---|
queued_record_purpose_check | CHECK ((purpose = ANY (ARRAY['import'::text, 'overlay'::text]))) |
Tables referencing this one via Foreign Key Constraints:
queued_bib_record_queue_idx queueTable: vandelay.queued_bib_record_attr
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
vandelay.queued_bib_record.id | record | bigint | NOT NULL |
vandelay.bib_attr_definition.id | field | integer | NOT NULL |
attr_value | text | NOT NULL |
Table: vandelay.queued_record
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
create_time | timestamp with time zone | NOT NULL DEFAULT now() | |
import_time | timestamp with time zone | ||
purpose | text | NOT NULL DEFAULT 'import'::text | |
marc | text | NOT NULL | |
quality | integer | NOT NULL |
Name | Constraint |
---|---|
queued_record_purpose_check | CHECK ((purpose = ANY (ARRAY['import'::text, 'overlay'::text]))) |
Table: vandelay.session_tracker
F-Key | Name | Type | Description |
---|---|---|---|
id | bigserial | PRIMARY KEY | |
session_key | text | NOT NULL | |
name | text | NOT NULL | |
actor.usr.id | usr | integer | NOT NULL |
actor.workstation.id | workstation | integer | NOT NULL |
record_type | text | NOT NULL DEFAULT 'bib'::text | |
queue | bigint | NOT NULL | |
create_time | timestamp with time zone | NOT NULL DEFAULT now() | |
update_time | timestamp with time zone | NOT NULL DEFAULT now() | |
state | text | NOT NULL DEFAULT 'active'::text | |
action_type | text | NOT NULL DEFAULT 'enqueue'::text | |
total_actions | integer | NOT NULL | |
actions_performed | integer | NOT NULL |
Name | Constraint |
---|---|
vand_tracker_valid_action_type | CHECK ((action_type = ANY (ARRAY['upload'::text, 'enqueue'::text, 'import'::text]))) |
vand_tracker_valid_record_type | CHECK ((record_type = ANY (ARRAY['bib'::text, 'authority'::text]))) |
vand_tracker_valid_state | CHECK ((state = ANY (ARRAY['active'::text, 'error'::text, 'complete'::text]))) |
Function: vandelay._get_expr_push_jrow(auth_heading vandelay.match_set_point, tags_rstore public.hstore, node text)
Returns: void
Language: PLPGSQL
DECLARE jrow TEXT; my_alias TEXT; op TEXT; tagkey TEXT; caseless BOOL; jrow_count INT; my_using TEXT; my_join TEXT; rec_table TEXT; BEGIN -- remember $1 is tags_rstore, and $2 is svf_rstore -- a non-NULL auth_heading means we're matching authority records IF auth_heading IS NOT NULL THEN rec_table := 'authority.full_rec'; ELSE rec_table := 'metabib.full_rec'; END IF; caseless := FALSE; SELECT COUNT(*) INTO jrow_count FROM _vandelay_tmp_jrows; IF jrow_count > 0 THEN my_using := ' USING (record)'; my_join := 'FULL OUTER JOIN'; ELSE my_using := ''; my_join := 'FROM'; END IF; IF node.tag IS NOT NULL THEN caseless := (node.tag IN ('020', '022', '024')); tagkey := node.tag; IF node.subfield IS NOT NULL THEN tagkey := tagkey || node.subfield; END IF; END IF; IF node.negate THEN IF caseless THEN op := 'NOT LIKE'; ELSE op := '<>'; END IF; ELSE IF caseless THEN op := 'LIKE'; ELSE op := '='; END IF; END IF; my_alias := 'n' || node.id::TEXT; jrow := my_join || ' (SELECT *, '; IF node.tag IS NOT NULL THEN jrow := jrow || node.quality || ' AS quality FROM ' || rec_table || ' mfr WHERE mfr.tag = ''' || node.tag || ''''; IF node.subfield IS NOT NULL THEN jrow := jrow || ' AND mfr.subfield = ''' || node.subfield || ''''; END IF; jrow := jrow || ' AND ('; jrow := jrow || vandelay._node_tag_comparisons(caseless, op, tags_rstore, tagkey); jrow := jrow || ')) ' || my_alias || my_using || E'\n'; ELSE -- svf IF auth_heading IS NOT NULL THEN -- authority record IF node.heading AND auth_heading <> '' THEN jrow := jrow || 'id AS record, ' || node.quality || ' AS quality FROM authority.record_entry are ' || ' WHERE are.heading = ''' || auth_heading || ''''; jrow := jrow || ') ' || my_alias || my_using || E'\n'; END IF; ELSE -- bib record jrow := jrow || 'id AS record, ' || node.quality || ' AS quality FROM metabib.record_attr_flat mraf WHERE mraf.attr = ''' || node.svf || ''' AND mraf.value ' || op || ' $2->''' || node.svf || ''') ' || my_alias || my_using || E'\n'; END IF; END IF; INSERT INTO _vandelay_tmp_jrows (j) VALUES (jrow); END;
Function: vandelay._get_expr_push_qrow(node vandelay.match_set_point)
Returns: void
Language: PLPGSQL
DECLARE BEGIN INSERT INTO _vandelay_tmp_qrows (q) VALUES (node.id); END;
Function: vandelay._get_expr_render_one(node vandelay.match_set_point)
Returns: text
Language: PLPGSQL
DECLARE s TEXT; BEGIN IF node.bool_op IS NOT NULL THEN RETURN node.bool_op; ELSE RETURN '(n' || node.id::TEXT || '.id IS NOT NULL)'; END IF; END;
Function: vandelay._node_tag_comparisons(tagkey boolean, tags_rstore text, op public.hstore, caseless text)
Returns: text
Language: PLPGSQL
DECLARE result TEXT; i INT; vals TEXT[]; BEGIN i := 1; vals := tags_rstore->tagkey; result := ''; WHILE TRUE LOOP IF i > 1 THEN IF vals[i] IS NULL THEN EXIT; ELSE result := result || ' OR '; END IF; END IF; IF caseless THEN result := result || 'LOWER(mfr.value) ' || op; ELSE result := result || 'mfr.value ' || op; END IF; result := result || ' ' || COALESCE('''' || vals[i] || '''', 'NULL'); IF vals[i] IS NULL THEN EXIT; END IF; i := i + 1; END LOOP; RETURN result; END;
Function: vandelay.add_field(field text, source_xml text, target_xml text)
Returns: text
Language: SQL
SELECT vandelay.add_field( $1, $2, $3, 0 );
Function: vandelay.add_field(force_add text, field text, source_xml text, target_xml integer)
Returns: text
Language: PLPERLU
use MARC::Record; use MARC::File::XML (BinaryEncoding => 'UTF-8'); use MARC::Charset; use strict; MARC::Charset->assume_unicode(1); my $target_xml = shift; my $source_xml = shift; my $field_spec = shift; my $force_add = shift || 0; my $target_r = MARC::Record->new_from_xml( $target_xml ); my $source_r = MARC::Record->new_from_xml( $source_xml ); return $target_xml unless ($target_r && $source_r); my @field_list = split(',', $field_spec); my %fields; for my $f (@field_list) { $f =~ s/^\s*//; $f =~ s/\s*$//; if ($f =~ /^(.{3})(\w*)(?:\[([^]]*)\])?$/) { my $field = $1; $field =~ s/\s+//; my $sf = $2; $sf =~ s/\s+//; my $match = $3; $match =~ s/^\s*//; $match =~ s/\s*$//; $fields{$field} = { sf => [ split('', $sf) ] }; if ($match) { my ($msf,$mre) = split('~', $match); if (length($msf) > 0 and length($mre) > 0) { $msf =~ s/^\s*//; $msf =~ s/\s*$//; $mre =~ s/^\s*//; $mre =~ s/\s*$//; $fields{$field}{match} = { sf => $msf, re => qr/$mre/ }; } } } } for my $f ( keys %fields) { if ( @{$fields{$f}{sf}} ) { for my $from_field ($source_r->field( $f )) { my @tos = $target_r->field( $f ); if (!@tos) { next if (exists($fields{$f}{match}) and !$force_add); my @new_fields = map { $_->clone } $source_r->field( $f ); $target_r->insert_fields_ordered( @new_fields ); } else { for my $to_field (@tos) { if (exists($fields{$f}{match})) { next unless (grep { $_ =~ $fields{$f}{match}{re} } $to_field->subfield($fields{$f}{match}{sf})); } for my $old_sf ($from_field->subfields) { $to_field->add_subfields( @$old_sf ) if grep(/$$old_sf[0]/,@{$fields{$f}{sf}}); } } } } } else { my @new_fields = map { $_->clone } $source_r->field( $f ); $target_r->insert_fields_ordered( @new_fields ); } } $target_xml = $target_r->as_xml_record; $target_xml =~ s/^<\?.+?\?>$//mo; $target_xml =~ s/\n//sgo; $target_xml =~ s/>\s+</></sgo; return $target_xml;
Function: vandelay.auto_overlay_authority_queue(merge_profile_id bigint, queue_id integer)
Returns: SET OF bigint
Language: PLPGSQL
DECLARE queued_record vandelay.queued_authority_record%ROWTYPE; BEGIN FOR queued_record IN SELECT * FROM vandelay.queued_authority_record WHERE queue = queue_id AND import_time IS NULL LOOP IF vandelay.auto_overlay_authority_record( queued_record.id, merge_profile_id ) THEN RETURN NEXT queued_record.id; END IF; END LOOP; RETURN; END;
Function: vandelay.auto_overlay_authority_queue(queue_id bigint)
Returns: SET OF bigint
Language: SQL
SELECT * FROM vandelay.auto_overlay_authority_queue( $1, NULL );
Function: vandelay.auto_overlay_authority_record(merge_profile_id bigint, import_id integer)
Returns: boolean
Language: PLPGSQL
DECLARE eg_id BIGINT; match_count INT; BEGIN SELECT COUNT(*) INTO match_count FROM vandelay.authority_match WHERE queued_record = import_id; IF match_count <> 1 THEN -- RAISE NOTICE 'not an exact match'; RETURN FALSE; END IF; SELECT m.eg_record INTO eg_id FROM vandelay.authority_match m WHERE m.queued_record = import_id LIMIT 1; IF eg_id IS NULL THEN RETURN FALSE; END IF; RETURN vandelay.overlay_authority_record( import_id, eg_id, merge_profile_id ); END;
Function: vandelay.auto_overlay_authority_record_with_best(lwm_ratio_value_p bigint, merge_profile_id integer, import_id numeric)
Returns: boolean
Language: PLPGSQL
DECLARE eg_id BIGINT; lwm_ratio_value NUMERIC; BEGIN lwm_ratio_value := COALESCE(lwm_ratio_value_p, 0.0); PERFORM * FROM vandelay.queued_authority_record WHERE import_time IS NOT NULL AND id = import_id; IF FOUND THEN -- RAISE NOTICE 'already imported, cannot auto-overlay' RETURN FALSE; END IF; SELECT m.eg_record INTO eg_id FROM vandelay.authority_match m JOIN vandelay.queued_authority_record qr ON (m.queued_record = qr.id) JOIN vandelay.authority_queue q ON (qr.queue = q.id) JOIN authority.record_entry r ON (r.id = m.eg_record) WHERE m.queued_record = import_id AND qr.quality::NUMERIC / COALESCE(NULLIF(m.quality,0),1)::NUMERIC >= lwm_ratio_value ORDER BY m.match_score DESC, -- required match score qr.quality::NUMERIC / COALESCE(NULLIF(m.quality,0),1)::NUMERIC DESC, -- quality tie breaker m.id -- when in doubt, use the first match LIMIT 1; IF eg_id IS NULL THEN -- RAISE NOTICE 'incoming record is not of high enough quality'; RETURN FALSE; END IF; RETURN vandelay.overlay_authority_record( import_id, eg_id, merge_profile_id ); END;
Function: vandelay.auto_overlay_bib_queue(merge_profile_id bigint, queue_id integer)
Returns: SET OF bigint
Language: PLPGSQL
DECLARE queued_record vandelay.queued_bib_record%ROWTYPE; BEGIN FOR queued_record IN SELECT * FROM vandelay.queued_bib_record WHERE queue = queue_id AND import_time IS NULL LOOP IF vandelay.auto_overlay_bib_record( queued_record.id, merge_profile_id ) THEN RETURN NEXT queued_record.id; END IF; END LOOP; RETURN; END;
Function: vandelay.auto_overlay_bib_queue(queue_id bigint)
Returns: SET OF bigint
Language: SQL
SELECT * FROM vandelay.auto_overlay_bib_queue( $1, NULL );
Function: vandelay.auto_overlay_bib_queue_with_best(lwm_ratio_value bigint, merge_profile_id integer, queue_id numeric)
Returns: SET OF bigint
Language: PLPGSQL
DECLARE queued_record vandelay.queued_bib_record%ROWTYPE; BEGIN FOR queued_record IN SELECT * FROM vandelay.queued_bib_record WHERE queue = queue_id AND import_time IS NULL LOOP IF vandelay.auto_overlay_bib_record_with_best( queued_record.id, merge_profile_id, lwm_ratio_value ) THEN RETURN NEXT queued_record.id; END IF; END LOOP; RETURN; END;
Function: vandelay.auto_overlay_bib_queue_with_best(merge_profile_id bigint, import_id integer)
Returns: SET OF bigint
Language: SQL
SELECT vandelay.auto_overlay_bib_queue_with_best( $1, $2, p.lwm_ratio ) FROM vandelay.merge_profile p WHERE id = $2;
Function: vandelay.auto_overlay_bib_record(merge_profile_id bigint, import_id integer)
Returns: boolean
Language: PLPGSQL
DECLARE eg_id BIGINT; match_count INT; BEGIN PERFORM * FROM vandelay.queued_bib_record WHERE import_time IS NOT NULL AND id = import_id; IF FOUND THEN -- RAISE NOTICE 'already imported, cannot auto-overlay' RETURN FALSE; END IF; SELECT COUNT(*) INTO match_count FROM vandelay.bib_match WHERE queued_record = import_id; IF match_count <> 1 THEN -- RAISE NOTICE 'not an exact match'; RETURN FALSE; END IF; -- Check that the one match is on the first 901c SELECT m.eg_record INTO eg_id FROM vandelay.queued_bib_record q JOIN vandelay.bib_match m ON (m.queued_record = q.id) WHERE q.id = import_id AND m.eg_record = oils_xpath_string('//*[@tag="901"]/*[@code="c"][1]',marc)::BIGINT; IF NOT FOUND THEN -- RAISE NOTICE 'not a 901c match'; RETURN FALSE; END IF; RETURN vandelay.overlay_bib_record( import_id, eg_id, merge_profile_id ); END;
Function: vandelay.auto_overlay_bib_record_with_best(lwm_ratio_value_p bigint, merge_profile_id integer, import_id numeric)
Returns: boolean
Language: PLPGSQL
DECLARE eg_id BIGINT; lwm_ratio_value NUMERIC; BEGIN lwm_ratio_value := COALESCE(lwm_ratio_value_p, 0.0); PERFORM * FROM vandelay.queued_bib_record WHERE import_time IS NOT NULL AND id = import_id; IF FOUND THEN -- RAISE NOTICE 'already imported, cannot auto-overlay' RETURN FALSE; END IF; SELECT m.eg_record INTO eg_id FROM vandelay.bib_match m JOIN vandelay.queued_bib_record qr ON (m.queued_record = qr.id) JOIN vandelay.bib_queue q ON (qr.queue = q.id) JOIN biblio.record_entry r ON (r.id = m.eg_record) WHERE m.queued_record = import_id AND qr.quality::NUMERIC / COALESCE(NULLIF(m.quality,0),1)::NUMERIC >= lwm_ratio_value ORDER BY m.match_score DESC, -- required match score qr.quality::NUMERIC / COALESCE(NULLIF(m.quality,0),1)::NUMERIC DESC, -- quality tie breaker m.id -- when in doubt, use the first match LIMIT 1; IF eg_id IS NULL THEN -- RAISE NOTICE 'incoming record is not of high enough quality'; RETURN FALSE; END IF; RETURN vandelay.overlay_bib_record( import_id, eg_id, merge_profile_id ); END;
Function: vandelay.auto_overlay_bib_record_with_best(merge_profile_id bigint, import_id integer)
Returns: boolean
Language: SQL
SELECT vandelay.auto_overlay_bib_record_with_best( $1, $2, p.lwm_ratio ) FROM vandelay.merge_profile p WHERE id = $2;
Function: vandelay.auto_overlay_org_unit_copies(lwm_ratio_value_p bigint, merge_profile_id integer, import_id numeric)
Returns: boolean
Language: PLPGSQL
DECLARE eg_id BIGINT; match_count INT; rec vandelay.bib_match%ROWTYPE; v_owning_lib INT; scope_org INT; scope_orgs INT[]; copy_count INT := 0; max_copy_count INT := 0; BEGIN PERFORM * FROM vandelay.queued_bib_record WHERE import_time IS NOT NULL AND id = import_id; IF FOUND THEN -- RAISE NOTICE 'already imported, cannot auto-overlay' RETURN FALSE; END IF; -- Gather all the owning libs for our import items. -- These are our initial scope_orgs. SELECT ARRAY_AGG(DISTINCT owning_lib) INTO scope_orgs FROM vandelay.import_item WHERE record = import_id; WHILE CARDINALITY(scope_orgs) > 0 LOOP FOR scope_org IN SELECT * FROM UNNEST(scope_orgs) LOOP -- For each match, get a count of all copies at descendants of our scope org. FOR rec IN SELECT * FROM vandelay.bib_match AS vbm WHERE queued_record = import_id ORDER BY vbm.eg_record DESC LOOP SELECT COUNT(acp.id) INTO copy_count FROM asset.copy AS acp INNER JOIN asset.call_number AS acn ON acp.call_number = acn.id WHERE acn.owning_lib IN (SELECT id FROM actor.org_unit_descendants(scope_org)) AND acn.record = rec.eg_record AND acp.deleted = FALSE; IF copy_count > max_copy_count THEN max_copy_count := copy_count; eg_id := rec.eg_record; END IF; END LOOP; END LOOP; -- If no matching bibs had holdings, gather our next set of orgs to check, and iterate. IF max_copy_count = 0 THEN SELECT ARRAY_AGG(DISTINCT parent_ou) INTO scope_orgs FROM actor.org_unit WHERE id IN (SELECT * FROM UNNEST(scope_orgs)) AND parent_ou IS NOT NULL; END IF; END LOOP; IF eg_id IS NULL THEN -- Could not determine best match via copy count -- fall back to default best match IF (SELECT * FROM vandelay.auto_overlay_bib_record_with_best( import_id, merge_profile_id, lwm_ratio_value_p )) THEN RETURN TRUE; ELSE RETURN FALSE; END IF; END IF; RETURN vandelay.overlay_bib_record( import_id, eg_id, merge_profile_id ); END;
Function: vandelay.cleanup_authority_marc()
Returns: trigger
Language: PLPGSQL
BEGIN IF TG_OP IN ('INSERT','UPDATE') AND NEW.imported_as IS NOT NULL THEN RETURN NEW; END IF; DELETE FROM vandelay.queued_authority_record_attr WHERE record = OLD.id; IF TG_OP = 'UPDATE' THEN RETURN NEW; END IF; RETURN OLD; END;
Function: vandelay.cleanup_bib_marc()
Returns: trigger
Language: PLPGSQL
BEGIN IF TG_OP IN ('INSERT','UPDATE') AND NEW.imported_as IS NOT NULL THEN RETURN NEW; END IF; DELETE FROM vandelay.queued_bib_record_attr WHERE record = OLD.id; DELETE FROM vandelay.import_item WHERE record = OLD.id; IF TG_OP = 'UPDATE' THEN RETURN NEW; END IF; RETURN OLD; END;
Function: vandelay.compile_profile(incoming_xml text)
Returns: compile_profile
Language: PLPGSQL
DECLARE output vandelay.compile_profile%ROWTYPE; profile vandelay.merge_profile%ROWTYPE; profile_tmpl TEXT; profile_tmpl_owner TEXT; add_rule TEXT := ''; strip_rule TEXT := ''; replace_rule TEXT := ''; preserve_rule TEXT := ''; BEGIN profile_tmpl := (oils_xpath('//*[@tag="905"]/*[@code="t"]/text()',incoming_xml))[1]; profile_tmpl_owner := (oils_xpath('//*[@tag="905"]/*[@code="o"]/text()',incoming_xml))[1]; IF profile_tmpl IS NOT NULL AND profile_tmpl <> '' AND profile_tmpl_owner IS NOT NULL AND profile_tmpl_owner <> '' THEN SELECT p.* INTO profile FROM vandelay.merge_profile p JOIN actor.org_unit u ON (u.id = p.owner) WHERE p.name = profile_tmpl AND u.shortname = profile_tmpl_owner; IF profile.id IS NOT NULL THEN add_rule := COALESCE(profile.add_spec,''); strip_rule := COALESCE(profile.strip_spec,''); replace_rule := COALESCE(profile.replace_spec,''); preserve_rule := COALESCE(profile.preserve_spec,''); END IF; END IF; add_rule := add_rule || ',' || COALESCE(ARRAY_TO_STRING(oils_xpath('//*[@tag="905"]/*[@code="a"]/text()',incoming_xml),','),''); strip_rule := strip_rule || ',' || COALESCE(ARRAY_TO_STRING(oils_xpath('//*[@tag="905"]/*[@code="d"]/text()',incoming_xml),','),''); replace_rule := replace_rule || ',' || COALESCE(ARRAY_TO_STRING(oils_xpath('//*[@tag="905"]/*[@code="r"]/text()',incoming_xml),','),''); preserve_rule := preserve_rule || ',' || COALESCE(ARRAY_TO_STRING(oils_xpath('//*[@tag="905"]/*[@code="p"]/text()',incoming_xml),','),''); output.add_rule := BTRIM(add_rule,','); output.replace_rule := BTRIM(replace_rule,','); output.strip_rule := BTRIM(strip_rule,','); output.preserve_rule := BTRIM(preserve_rule,','); RETURN output; END;
Function: vandelay.extract_rec_attrs(attr_defs text, xml text[])
Returns: hstore
Language: PLPGSQL
DECLARE transformed_xml TEXT; prev_xfrm TEXT; normalizer RECORD; xfrm config.xml_transform%ROWTYPE; attr_value TEXT; new_attrs HSTORE := ''::HSTORE; attr_def config.record_attr_definition%ROWTYPE; BEGIN FOR attr_def IN SELECT * FROM config.record_attr_definition WHERE name IN (SELECT * FROM UNNEST(attr_defs)) ORDER BY format LOOP IF attr_def.tag IS NOT NULL THEN -- tag (and optional subfield list) selection SELECT STRING_AGG(x.value, COALESCE(attr_def.joiner,' ')) INTO attr_value FROM vandelay.flatten_marc(xml) AS x WHERE x.tag LIKE attr_def.tag AND CASE WHEN attr_def.sf_list IS NOT NULL THEN POSITION(x.subfield IN attr_def.sf_list) > 0 ELSE TRUE END GROUP BY x.tag ORDER BY x.tag LIMIT 1; ELSIF attr_def.fixed_field IS NOT NULL THEN -- a named fixed field, see config.marc21_ff_pos_map.fixed_field attr_value := vandelay.marc21_extract_fixed_field(xml, attr_def.fixed_field); ELSIF attr_def.xpath IS NOT NULL THEN -- and xpath expression SELECT INTO xfrm * FROM config.xml_transform WHERE name = attr_def.format; -- See if we can skip the XSLT ... it's expensive IF prev_xfrm IS NULL OR prev_xfrm <> xfrm.name THEN -- Can't skip the transform IF xfrm.xslt <> '---' THEN transformed_xml := oils_xslt_process(xml,xfrm.xslt); ELSE transformed_xml := xml; END IF; prev_xfrm := xfrm.name; END IF; IF xfrm.name IS NULL THEN -- just grab the marcxml (empty) transform SELECT INTO xfrm * FROM config.xml_transform WHERE xslt = '---' LIMIT 1; prev_xfrm := xfrm.name; END IF; attr_value := oils_xpath_string(attr_def.xpath, transformed_xml, COALESCE(attr_def.joiner,' '), ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]]); ELSIF attr_def.phys_char_sf IS NOT NULL THEN -- a named Physical Characteristic, see config.marc21_physical_characteristic_*_map SELECT m.value::TEXT INTO attr_value FROM vandelay.marc21_physical_characteristics(xml) v JOIN config.marc21_physical_characteristic_value_map m ON (m.id = v.value) WHERE v.subfield = attr_def.phys_char_sf LIMIT 1; -- Just in case ... END IF; -- apply index normalizers to attr_value FOR normalizer IN SELECT n.func AS func, n.param_count AS param_count, m.params AS params FROM config.index_normalizer n JOIN config.record_attr_index_norm_map m ON (m.norm = n.id) WHERE attr = attr_def.name ORDER BY m.pos LOOP EXECUTE 'SELECT ' || normalizer.func || '(' || quote_nullable( attr_value ) || CASE WHEN normalizer.param_count > 0 THEN ',' || REPLACE(REPLACE(BTRIM(normalizer.params,'[]'),E'\'',E'\\\''),E'"',E'\'') ELSE '' END || ')' INTO attr_value; END LOOP; -- Add the new value to the hstore new_attrs := new_attrs || hstore( attr_def.name, attr_value ); END LOOP; RETURN new_attrs; END;
Function: vandelay.extract_rec_attrs(xml text)
Returns: hstore
Language: SQL
SELECT vandelay.extract_rec_attrs( $1, (SELECT ARRAY_AGG(name) FROM config.record_attr_definition));
Function: vandelay.find_bib_tcn_data(xml text)
Returns: SET OF tcn_data
Language: PLPGSQL
DECLARE eg_tcn TEXT; eg_tcn_source TEXT; output vandelay.tcn_data%ROWTYPE; BEGIN -- 001/003 eg_tcn := BTRIM((oils_xpath('//*[@tag="001"]/text()',xml))[1]); IF eg_tcn IS NOT NULL AND eg_tcn <> '' THEN eg_tcn_source := BTRIM((oils_xpath('//*[@tag="003"]/text()',xml))[1]); IF eg_tcn_source IS NULL OR eg_tcn_source = '' THEN eg_tcn_source := 'System Local'; END IF; PERFORM id FROM biblio.record_entry WHERE tcn_value = eg_tcn AND NOT deleted; IF NOT FOUND THEN output.used := FALSE; ELSE output.used := TRUE; END IF; output.tcn := eg_tcn; output.tcn_source := eg_tcn_source; RETURN NEXT output; END IF; -- 901 ab eg_tcn := BTRIM((oils_xpath('//*[@tag="901"]/*[@code="a"]/text()',xml))[1]); IF eg_tcn IS NOT NULL AND eg_tcn <> '' THEN eg_tcn_source := BTRIM((oils_xpath('//*[@tag="901"]/*[@code="b"]/text()',xml))[1]); IF eg_tcn_source IS NULL OR eg_tcn_source = '' THEN eg_tcn_source := 'System Local'; END IF; PERFORM id FROM biblio.record_entry WHERE tcn_value = eg_tcn AND NOT deleted; IF NOT FOUND THEN output.used := FALSE; ELSE output.used := TRUE; END IF; output.tcn := eg_tcn; output.tcn_source := eg_tcn_source; RETURN NEXT output; END IF; -- 039 ab eg_tcn := BTRIM((oils_xpath('//*[@tag="039"]/*[@code="a"]/text()',xml))[1]); IF eg_tcn IS NOT NULL AND eg_tcn <> '' THEN eg_tcn_source := BTRIM((oils_xpath('//*[@tag="039"]/*[@code="b"]/text()',xml))[1]); IF eg_tcn_source IS NULL OR eg_tcn_source = '' THEN eg_tcn_source := 'System Local'; END IF; PERFORM id FROM biblio.record_entry WHERE tcn_value = eg_tcn AND NOT deleted; IF NOT FOUND THEN output.used := FALSE; ELSE output.used := TRUE; END IF; output.tcn := eg_tcn; output.tcn_source := eg_tcn_source; RETURN NEXT output; END IF; -- 020 a eg_tcn := REGEXP_REPLACE((oils_xpath('//*[@tag="020"]/*[@code="a"]/text()',xml))[1], $re$^(\w+).*?$$re$, $re$\1$re$); IF eg_tcn IS NOT NULL AND eg_tcn <> '' THEN eg_tcn_source := 'ISBN'; PERFORM id FROM biblio.record_entry WHERE tcn_value = eg_tcn AND NOT deleted; IF NOT FOUND THEN output.used := FALSE; ELSE output.used := TRUE; END IF; output.tcn := eg_tcn; output.tcn_source := eg_tcn_source; RETURN NEXT output; END IF; -- 022 a eg_tcn := REGEXP_REPLACE((oils_xpath('//*[@tag="022"]/*[@code="a"]/text()',xml))[1], $re$^(\w+).*?$$re$, $re$\1$re$); IF eg_tcn IS NOT NULL AND eg_tcn <> '' THEN eg_tcn_source := 'ISSN'; PERFORM id FROM biblio.record_entry WHERE tcn_value = eg_tcn AND NOT deleted; IF NOT FOUND THEN output.used := FALSE; ELSE output.used := TRUE; END IF; output.tcn := eg_tcn; output.tcn_source := eg_tcn_source; RETURN NEXT output; END IF; -- 010 a eg_tcn := REGEXP_REPLACE((oils_xpath('//*[@tag="010"]/*[@code="a"]/text()',xml))[1], $re$^(\w+).*?$$re$, $re$\1$re$); IF eg_tcn IS NOT NULL AND eg_tcn <> '' THEN eg_tcn_source := 'LCCN'; PERFORM id FROM biblio.record_entry WHERE tcn_value = eg_tcn AND NOT deleted; IF NOT FOUND THEN output.used := FALSE; ELSE output.used := TRUE; END IF; output.tcn := eg_tcn; output.tcn_source := eg_tcn_source; RETURN NEXT output; END IF; -- 035 a eg_tcn := REGEXP_REPLACE((oils_xpath('//*[@tag="035"]/*[@code="a"]/text()',xml))[1], $re$^.*?(\w+)$$re$, $re$\1$re$); IF eg_tcn IS NOT NULL AND eg_tcn <> '' THEN eg_tcn_source := 'System Legacy'; PERFORM id FROM biblio.record_entry WHERE tcn_value = eg_tcn AND NOT deleted; IF NOT FOUND THEN output.used := FALSE; ELSE output.used := TRUE; END IF; output.tcn := eg_tcn; output.tcn_source := eg_tcn_source; RETURN NEXT output; END IF; RETURN; END;
Function: vandelay.flatten_marc(marc text)
Returns: SET OF flat_marc
Language: PLPGSQL
DECLARE output vandelay.flat_marc%ROWTYPE; field RECORD; BEGIN FOR field IN SELECT * FROM vandelay.flay_marc( marc ) LOOP output.ind1 := field.ind1; output.ind2 := field.ind2; output.tag := field.tag; output.subfield := field.subfield; IF field.subfield IS NOT NULL AND field.tag NOT IN ('020','022','024') THEN -- exclude standard numbers and control fields output.value := naco_normalize(field.value, field.subfield); ELSE output.value := field.value; END IF; CONTINUE WHEN output.value IS NULL; RETURN NEXT output; END LOOP; END;
Function: vandelay.flatten_marc_hstore(record_xml text)
Returns: hstore
Language: PLPGSQL
BEGIN RETURN (SELECT HSTORE( ARRAY_AGG(tag || (COALESCE(subfield, ''))), ARRAY_AGG(value) ) FROM ( SELECT tag, subfield, ARRAY_AGG(value)::TEXT AS value FROM (SELECT tag, subfield, CASE WHEN tag = '020' THEN -- caseless -- isbn LOWER((SELECT REGEXP_MATCHES(value,$$^(\S{10,17})$$))[1] || '%') WHEN tag = '022' THEN -- caseless -- issn LOWER((SELECT REGEXP_MATCHES(value,$$^(\S{4}[- ]?\S{4})$$))[1] || '%') WHEN tag = '024' THEN -- caseless -- upc (other) LOWER(value || '%') ELSE value END AS value FROM vandelay.flatten_marc(record_xml)) x GROUP BY tag, subfield ORDER BY tag, subfield ) subquery ); END;
Function: vandelay.flay_marc(text)
Returns: SET OF flat_marc
Language: PLPERLU
use MARC::Record; use MARC::File::XML (BinaryEncoding => 'UTF-8'); use MARC::Charset; use strict; MARC::Charset->assume_unicode(1); my $xml = shift; my $r = MARC::Record->new_from_xml( $xml ); return_next( { tag => 'LDR', value => $r->leader } ); for my $f ( $r->fields ) { if ($f->is_control_field) { return_next({ tag => $f->tag, value => $f->data }); } else { for my $s ($f->subfields) { return_next({ tag => $f->tag, ind1 => $f->indicator(1), ind2 => $f->indicator(2), subfield => $s->[0], value => $s->[1] }); if ( $f->tag eq '245' and $s->[0] eq 'a' ) { my $trim = $f->indicator(2) || 0; return_next({ tag => 'tnf', ind1 => $f->indicator(1), ind2 => $f->indicator(2), subfield => 'a', value => substr( $s->[1], $trim ) }); } } } } return undef;
Function: vandelay.get_expr_from_match_set(auth_heading integer, tags_rstore public.hstore, match_set_id text)
Returns: text
Language: PLPGSQL
DECLARE root vandelay.match_set_point; BEGIN SELECT * INTO root FROM vandelay.match_set_point WHERE parent IS NULL AND match_set = match_set_id; RETURN vandelay.get_expr_from_match_set_point( root, tags_rstore, auth_heading); END;
Function: vandelay.get_expr_from_match_set(tags_rstore integer, match_set_id public.hstore)
Returns: text
Language: PLPGSQL
BEGIN RETURN vandelay.get_expr_from_match_set( match_set_id, tags_rstore, NULL); END;
Function: vandelay.get_expr_from_match_set_point(auth_heading vandelay.match_set_point, tags_rstore public.hstore, node text)
Returns: text
Language: PLPGSQL
DECLARE q TEXT; i INTEGER; this_op TEXT; children INTEGER[]; child vandelay.match_set_point; BEGIN SELECT ARRAY_AGG(id) INTO children FROM vandelay.match_set_point WHERE parent = node.id; IF ARRAY_LENGTH(children, 1) > 0 THEN this_op := vandelay._get_expr_render_one(node); q := '('; i := 1; WHILE children[i] IS NOT NULL LOOP SELECT * INTO child FROM vandelay.match_set_point WHERE id = children[i]; IF i > 1 THEN q := q || ' ' || this_op || ' '; END IF; i := i + 1; q := q || vandelay.get_expr_from_match_set_point( child, tags_rstore, auth_heading); END LOOP; q := q || ')'; RETURN q; ELSIF node.bool_op IS NULL THEN PERFORM vandelay._get_expr_push_qrow(node); PERFORM vandelay._get_expr_push_jrow(node, tags_rstore, auth_heading); RETURN vandelay._get_expr_render_one(node); ELSE RETURN ''; END IF; END;
Function: vandelay.ingest_authority_marc()
Returns: trigger
Language: PLPGSQL
DECLARE value TEXT; atype TEXT; adef RECORD; BEGIN IF TG_OP IN ('INSERT','UPDATE') AND NEW.imported_as IS NOT NULL THEN RETURN NEW; END IF; FOR adef IN SELECT * FROM vandelay.authority_attr_definition LOOP SELECT extract_marc_field('vandelay.queued_authority_record', id, adef.xpath, adef.remove) INTO value FROM vandelay.queued_authority_record WHERE id = NEW.id; IF (value IS NOT NULL AND value <> '') THEN INSERT INTO vandelay.queued_authority_record_attr (record, field, attr_value) VALUES (NEW.id, adef.id, value); END IF; END LOOP; RETURN NULL; END;
Function: vandelay.ingest_bib_items()
Returns: trigger
Language: PLPGSQL
DECLARE attr_def BIGINT; item_data vandelay.import_item%ROWTYPE; BEGIN IF TG_OP IN ('INSERT','UPDATE') AND NEW.imported_as IS NOT NULL THEN RETURN NEW; END IF; SELECT item_attr_def INTO attr_def FROM vandelay.bib_queue WHERE id = NEW.queue; FOR item_data IN SELECT * FROM vandelay.ingest_items( NEW.id::BIGINT, attr_def ) LOOP INSERT INTO vandelay.import_item ( record, definition, owning_lib, circ_lib, call_number, copy_number, status, location, circulate, deposit, deposit_amount, ref, holdable, price, barcode, circ_modifier, circ_as_type, alert_message, pub_note, priv_note, internal_id, opac_visible, stat_cat_data, parts_data, import_error, error_detail ) VALUES ( NEW.id, item_data.definition, item_data.owning_lib, item_data.circ_lib, item_data.call_number, item_data.copy_number, item_data.status, item_data.location, item_data.circulate, item_data.deposit, item_data.deposit_amount, item_data.ref, item_data.holdable, item_data.price, item_data.barcode, item_data.circ_modifier, item_data.circ_as_type, item_data.alert_message, item_data.pub_note, item_data.priv_note, item_data.internal_id, item_data.opac_visible, item_data.stat_cat_data, item_data.parts_data, item_data.import_error, item_data.error_detail ); END LOOP; RETURN NULL; END;
Function: vandelay.ingest_bib_marc()
Returns: trigger
Language: PLPGSQL
DECLARE value TEXT; atype TEXT; adef RECORD; BEGIN IF TG_OP IN ('INSERT','UPDATE') AND NEW.imported_as IS NOT NULL THEN RETURN NEW; END IF; FOR adef IN SELECT * FROM vandelay.bib_attr_definition LOOP SELECT extract_marc_field('vandelay.queued_bib_record', id, adef.xpath, adef.remove) INTO value FROM vandelay.queued_bib_record WHERE id = NEW.id; IF (value IS NOT NULL AND value <> '') THEN INSERT INTO vandelay.queued_bib_record_attr (record, field, attr_value) VALUES (NEW.id, adef.id, value); END IF; END LOOP; RETURN NULL; END;
Function: vandelay.ingest_items(attr_def_id bigint, import_id bigint)
Returns: SET OF import_item
Language: PLPGSQL
DECLARE owning_lib TEXT; circ_lib TEXT; call_number TEXT; copy_number TEXT; status TEXT; location TEXT; circulate TEXT; deposit TEXT; deposit_amount TEXT; ref TEXT; holdable TEXT; price TEXT; barcode TEXT; circ_modifier TEXT; circ_as_type TEXT; alert_message TEXT; opac_visible TEXT; pub_note TEXT; priv_note TEXT; internal_id TEXT; stat_cat_data TEXT; parts_data TEXT; attr_def RECORD; tmp_attr_set RECORD; attr_set vandelay.import_item%ROWTYPE; xpaths TEXT[]; tmp_str TEXT; BEGIN SELECT * INTO attr_def FROM vandelay.import_item_attr_definition WHERE id = attr_def_id; IF FOUND THEN attr_set.definition := attr_def.id; -- Build the combined XPath owning_lib := CASE WHEN attr_def.owning_lib IS NULL THEN 'null()' WHEN LENGTH( attr_def.owning_lib ) = 1 THEN '//*[@code="' || attr_def.owning_lib || '"]' ELSE '//*' || attr_def.owning_lib END; circ_lib := CASE WHEN attr_def.circ_lib IS NULL THEN 'null()' WHEN LENGTH( attr_def.circ_lib ) = 1 THEN '//*[@code="' || attr_def.circ_lib || '"]' ELSE '//*' || attr_def.circ_lib END; call_number := CASE WHEN attr_def.call_number IS NULL THEN 'null()' WHEN LENGTH( attr_def.call_number ) = 1 THEN '//*[@code="' || attr_def.call_number || '"]' ELSE '//*' || attr_def.call_number END; copy_number := CASE WHEN attr_def.copy_number IS NULL THEN 'null()' WHEN LENGTH( attr_def.copy_number ) = 1 THEN '//*[@code="' || attr_def.copy_number || '"]' ELSE '//*' || attr_def.copy_number END; status := CASE WHEN attr_def.status IS NULL THEN 'null()' WHEN LENGTH( attr_def.status ) = 1 THEN '//*[@code="' || attr_def.status || '"]' ELSE '//*' || attr_def.status END; location := CASE WHEN attr_def.location IS NULL THEN 'null()' WHEN LENGTH( attr_def.location ) = 1 THEN '//*[@code="' || attr_def.location || '"]' ELSE '//*' || attr_def.location END; circulate := CASE WHEN attr_def.circulate IS NULL THEN 'null()' WHEN LENGTH( attr_def.circulate ) = 1 THEN '//*[@code="' || attr_def.circulate || '"]' ELSE '//*' || attr_def.circulate END; deposit := CASE WHEN attr_def.deposit IS NULL THEN 'null()' WHEN LENGTH( attr_def.deposit ) = 1 THEN '//*[@code="' || attr_def.deposit || '"]' ELSE '//*' || attr_def.deposit END; deposit_amount := CASE WHEN attr_def.deposit_amount IS NULL THEN 'null()' WHEN LENGTH( attr_def.deposit_amount ) = 1 THEN '//*[@code="' || attr_def.deposit_amount || '"]' ELSE '//*' || attr_def.deposit_amount END; ref := CASE WHEN attr_def.ref IS NULL THEN 'null()' WHEN LENGTH( attr_def.ref ) = 1 THEN '//*[@code="' || attr_def.ref || '"]' ELSE '//*' || attr_def.ref END; holdable := CASE WHEN attr_def.holdable IS NULL THEN 'null()' WHEN LENGTH( attr_def.holdable ) = 1 THEN '//*[@code="' || attr_def.holdable || '"]' ELSE '//*' || attr_def.holdable END; price := CASE WHEN attr_def.price IS NULL THEN 'null()' WHEN LENGTH( attr_def.price ) = 1 THEN '//*[@code="' || attr_def.price || '"]' ELSE '//*' || attr_def.price END; barcode := CASE WHEN attr_def.barcode IS NULL THEN 'null()' WHEN LENGTH( attr_def.barcode ) = 1 THEN '//*[@code="' || attr_def.barcode || '"]' ELSE '//*' || attr_def.barcode END; circ_modifier := CASE WHEN attr_def.circ_modifier IS NULL THEN 'null()' WHEN LENGTH( attr_def.circ_modifier ) = 1 THEN '//*[@code="' || attr_def.circ_modifier || '"]' ELSE '//*' || attr_def.circ_modifier END; circ_as_type := CASE WHEN attr_def.circ_as_type IS NULL THEN 'null()' WHEN LENGTH( attr_def.circ_as_type ) = 1 THEN '//*[@code="' || attr_def.circ_as_type || '"]' ELSE '//*' || attr_def.circ_as_type END; alert_message := CASE WHEN attr_def.alert_message IS NULL THEN 'null()' WHEN LENGTH( attr_def.alert_message ) = 1 THEN '//*[@code="' || attr_def.alert_message || '"]' ELSE '//*' || attr_def.alert_message END; opac_visible := CASE WHEN attr_def.opac_visible IS NULL THEN 'null()' WHEN LENGTH( attr_def.opac_visible ) = 1 THEN '//*[@code="' || attr_def.opac_visible || '"]' ELSE '//*' || attr_def.opac_visible END; pub_note := CASE WHEN attr_def.pub_note IS NULL THEN 'null()' WHEN LENGTH( attr_def.pub_note ) = 1 THEN '//*[@code="' || attr_def.pub_note || '"]' ELSE '//*' || attr_def.pub_note END; priv_note := CASE WHEN attr_def.priv_note IS NULL THEN 'null()' WHEN LENGTH( attr_def.priv_note ) = 1 THEN '//*[@code="' || attr_def.priv_note || '"]' ELSE '//*' || attr_def.priv_note END; internal_id := CASE WHEN attr_def.internal_id IS NULL THEN 'null()' WHEN LENGTH( attr_def.internal_id ) = 1 THEN '//*[@code="' || attr_def.internal_id || '"]' ELSE '//*' || attr_def.internal_id END; stat_cat_data := CASE WHEN attr_def.stat_cat_data IS NULL THEN 'null()' WHEN LENGTH( attr_def.stat_cat_data ) = 1 THEN '//*[@code="' || attr_def.stat_cat_data || '"]' ELSE '//*' || attr_def.stat_cat_data END; parts_data := CASE WHEN attr_def.parts_data IS NULL THEN 'null()' WHEN LENGTH( attr_def.parts_data ) = 1 THEN '//*[@code="' || attr_def.parts_data || '"]' ELSE '//*' || attr_def.parts_data END; xpaths := ARRAY[owning_lib, circ_lib, call_number, copy_number, status, location, circulate, deposit, deposit_amount, ref, holdable, price, barcode, circ_modifier, circ_as_type, alert_message, pub_note, priv_note, internal_id, stat_cat_data, parts_data, opac_visible]; FOR tmp_attr_set IN SELECT * FROM oils_xpath_tag_to_table( (SELECT marc FROM vandelay.queued_bib_record WHERE id = import_id), attr_def.tag, xpaths) AS t( ol TEXT, clib TEXT, cn TEXT, cnum TEXT, cs TEXT, cl TEXT, circ TEXT, dep TEXT, dep_amount TEXT, r TEXT, hold TEXT, pr TEXT, bc TEXT, circ_mod TEXT, circ_as TEXT, amessage TEXT, note TEXT, pnote TEXT, internal_id TEXT, stat_cat_data TEXT, parts_data TEXT, opac_vis TEXT ) LOOP attr_set.import_error := NULL; attr_set.error_detail := NULL; attr_set.deposit_amount := NULL; attr_set.copy_number := NULL; attr_set.price := NULL; attr_set.circ_modifier := NULL; attr_set.location := NULL; attr_set.barcode := NULL; attr_set.call_number := NULL; IF tmp_attr_set.pr != '' THEN tmp_str = REGEXP_REPLACE(tmp_attr_set.pr, E'[^0-9\\.]', '', 'g'); IF tmp_str = '' THEN attr_set.import_error := 'import.item.invalid.price'; attr_set.error_detail := tmp_attr_set.pr; -- original value RETURN NEXT attr_set; CONTINUE; END IF; attr_set.price := tmp_str::NUMERIC(8,2); END IF; IF tmp_attr_set.dep_amount != '' THEN tmp_str = REGEXP_REPLACE(tmp_attr_set.dep_amount, E'[^0-9\\.]', '', 'g'); IF tmp_str = '' THEN attr_set.import_error := 'import.item.invalid.deposit_amount'; attr_set.error_detail := tmp_attr_set.dep_amount; RETURN NEXT attr_set; CONTINUE; END IF; attr_set.deposit_amount := tmp_str::NUMERIC(8,2); END IF; IF tmp_attr_set.cnum != '' THEN tmp_str = REGEXP_REPLACE(tmp_attr_set.cnum, E'[^0-9]', '', 'g'); IF tmp_str = '' THEN attr_set.import_error := 'import.item.invalid.copy_number'; attr_set.error_detail := tmp_attr_set.cnum; RETURN NEXT attr_set; CONTINUE; END IF; attr_set.copy_number := tmp_str::INT; END IF; IF tmp_attr_set.ol != '' THEN SELECT id INTO attr_set.owning_lib FROM actor.org_unit WHERE shortname = UPPER(tmp_attr_set.ol); -- INT IF NOT FOUND THEN attr_set.import_error := 'import.item.invalid.owning_lib'; attr_set.error_detail := tmp_attr_set.ol; RETURN NEXT attr_set; CONTINUE; END IF; END IF; IF tmp_attr_set.clib != '' THEN SELECT id INTO attr_set.circ_lib FROM actor.org_unit WHERE shortname = UPPER(tmp_attr_set.clib); -- INT IF NOT FOUND THEN attr_set.import_error := 'import.item.invalid.circ_lib'; attr_set.error_detail := tmp_attr_set.clib; RETURN NEXT attr_set; CONTINUE; END IF; END IF; IF tmp_attr_set.cs != '' THEN SELECT id INTO attr_set.status FROM config.copy_status WHERE LOWER(name) = LOWER(tmp_attr_set.cs); -- INT IF NOT FOUND THEN attr_set.import_error := 'import.item.invalid.status'; attr_set.error_detail := tmp_attr_set.cs; RETURN NEXT attr_set; CONTINUE; END IF; END IF; IF COALESCE(tmp_attr_set.circ_mod, '') = '' THEN -- no circ mod defined, see if we should apply a default SELECT INTO attr_set.circ_modifier TRIM(BOTH '"' FROM value) FROM actor.org_unit_ancestor_setting( 'vandelay.item.circ_modifier.default', attr_set.owning_lib ); -- make sure the value from the org setting is still valid PERFORM 1 FROM config.circ_modifier WHERE code = attr_set.circ_modifier; IF NOT FOUND THEN attr_set.import_error := 'import.item.invalid.circ_modifier'; attr_set.error_detail := tmp_attr_set.circ_mod; RETURN NEXT attr_set; CONTINUE; END IF; ELSE SELECT code INTO attr_set.circ_modifier FROM config.circ_modifier WHERE code = tmp_attr_set.circ_mod; IF NOT FOUND THEN attr_set.import_error := 'import.item.invalid.circ_modifier'; attr_set.error_detail := tmp_attr_set.circ_mod; RETURN NEXT attr_set; CONTINUE; END IF; END IF; IF tmp_attr_set.circ_as != '' THEN SELECT code INTO attr_set.circ_as_type FROM config.coded_value_map WHERE ctype = 'item_type' AND code = tmp_attr_set.circ_as; IF NOT FOUND THEN attr_set.import_error := 'import.item.invalid.circ_as_type'; attr_set.error_detail := tmp_attr_set.circ_as; RETURN NEXT attr_set; CONTINUE; END IF; END IF; IF COALESCE(tmp_attr_set.cl, '') = '' THEN -- no location specified, see if we should apply a default SELECT INTO attr_set.location TRIM(BOTH '"' FROM value) FROM actor.org_unit_ancestor_setting( 'vandelay.item.copy_location.default', attr_set.owning_lib ); -- make sure the value from the org setting is still valid PERFORM 1 FROM asset.copy_location WHERE id = attr_set.location AND NOT deleted; IF NOT FOUND THEN attr_set.import_error := 'import.item.invalid.location'; attr_set.error_detail := tmp_attr_set.cs; RETURN NEXT attr_set; CONTINUE; END IF; ELSE -- search up the org unit tree for a matching copy location WITH RECURSIVE anscestor_depth AS ( SELECT ou.id, out.depth AS depth, ou.parent_ou FROM actor.org_unit ou JOIN actor.org_unit_type out ON (out.id = ou.ou_type) WHERE ou.id = COALESCE(attr_set.owning_lib, attr_set.circ_lib) UNION ALL SELECT ou.id, out.depth, ou.parent_ou FROM actor.org_unit ou JOIN actor.org_unit_type out ON (out.id = ou.ou_type) JOIN anscestor_depth ot ON (ot.parent_ou = ou.id) ) SELECT cpl.id INTO attr_set.location FROM anscestor_depth a JOIN asset.copy_location cpl ON (cpl.owning_lib = a.id) WHERE LOWER(cpl.name) = LOWER(tmp_attr_set.cl) AND NOT cpl.deleted ORDER BY a.depth DESC LIMIT 1; IF NOT FOUND THEN attr_set.import_error := 'import.item.invalid.location'; attr_set.error_detail := tmp_attr_set.cs; RETURN NEXT attr_set; CONTINUE; END IF; END IF; attr_set.circulate := LOWER( SUBSTRING( tmp_attr_set.circ, 1, 1)) IN ('t','y','1') OR LOWER(tmp_attr_set.circ) = 'circulating'; -- BOOL attr_set.deposit := LOWER( SUBSTRING( tmp_attr_set.dep, 1, 1 ) ) IN ('t','y','1') OR LOWER(tmp_attr_set.dep) = 'deposit'; -- BOOL attr_set.holdable := LOWER( SUBSTRING( tmp_attr_set.hold, 1, 1 ) ) IN ('t','y','1') OR LOWER(tmp_attr_set.hold) = 'holdable'; -- BOOL attr_set.opac_visible := LOWER( SUBSTRING( tmp_attr_set.opac_vis, 1, 1 ) ) IN ('t','y','1') OR LOWER(tmp_attr_set.opac_vis) = 'visible'; -- BOOL attr_set.ref := LOWER( SUBSTRING( tmp_attr_set.r, 1, 1 ) ) IN ('t','y','1') OR LOWER(tmp_attr_set.r) = 'reference'; -- BOOL attr_set.call_number := tmp_attr_set.cn; -- TEXT attr_set.barcode := tmp_attr_set.bc; -- TEXT, attr_set.alert_message := tmp_attr_set.amessage; -- TEXT, attr_set.pub_note := tmp_attr_set.note; -- TEXT, attr_set.priv_note := tmp_attr_set.pnote; -- TEXT, attr_set.alert_message := tmp_attr_set.amessage; -- TEXT, attr_set.internal_id := tmp_attr_set.internal_id::BIGINT; attr_set.stat_cat_data := tmp_attr_set.stat_cat_data; -- TEXT, attr_set.parts_data := tmp_attr_set.parts_data; -- TEXT, RETURN NEXT attr_set; END LOOP; END IF; RETURN; END;
Function: vandelay.marc21_extract_all_fixed_fields(use_default text, marc boolean)
Returns: SET OF record_ff_map
Language: PLPGSQL
DECLARE tag_data TEXT; rtype TEXT; ff_pos RECORD; output biblio.record_ff_map%ROWTYPE; BEGIN rtype := (vandelay.marc21_record_type( marc )).code; FOR ff_pos IN SELECT * FROM config.marc21_ff_pos_map WHERE rec_type = rtype ORDER BY tag DESC LOOP output.ff_name := ff_pos.fixed_field; output.ff_value := NULL; IF ff_pos.tag = 'ldr' THEN output.ff_value := oils_xpath_string('//*[local-name()="leader"]', marc); IF output.ff_value IS NOT NULL THEN output.ff_value := SUBSTRING( output.ff_value, ff_pos.start_pos + 1, ff_pos.length ); RETURN NEXT output; output.ff_value := NULL; END IF; ELSE FOR tag_data IN SELECT value FROM UNNEST( oils_xpath( '//*[@tag="' || UPPER(ff_pos.tag) || '"]/text()', marc ) ) x(value) LOOP output.ff_value := SUBSTRING( tag_data, ff_pos.start_pos + 1, ff_pos.length ); CONTINUE WHEN output.ff_value IS NULL AND NOT use_default; IF output.ff_value IS NULL THEN output.ff_value := REPEAT( ff_pos.default_val, ff_pos.length ); END IF; RETURN NEXT output; output.ff_value := NULL; END LOOP; END IF; END LOOP; RETURN; END;
Function: vandelay.marc21_extract_fixed_field(use_default text, ff text, marc boolean)
Returns: text
Language: PLPGSQL
DECLARE rtype TEXT; ff_pos RECORD; tag_data RECORD; val TEXT; BEGIN rtype := (vandelay.marc21_record_type( marc )).code; FOR ff_pos IN SELECT * FROM config.marc21_ff_pos_map WHERE fixed_field = ff AND rec_type = rtype ORDER BY tag DESC LOOP IF ff_pos.tag = 'ldr' THEN val := oils_xpath_string('//*[local-name()="leader"]', marc); IF val IS NOT NULL THEN val := SUBSTRING( val, ff_pos.start_pos + 1, ff_pos.length ); RETURN val; END IF; ELSE FOR tag_data IN SELECT value FROM UNNEST( oils_xpath( '//*[@tag="' || UPPER(ff_pos.tag) || '"]/text()', marc ) ) x(value) LOOP val := SUBSTRING( tag_data.value, ff_pos.start_pos + 1, ff_pos.length ); RETURN val; END LOOP; END IF; CONTINUE WHEN NOT use_default; val := REPEAT( ff_pos.default_val, ff_pos.length ); RETURN val; END LOOP; RETURN NULL; END;
Function: vandelay.marc21_extract_fixed_field_list(use_default text, ff text, marc boolean)
Returns: text[]
Language: PLPGSQL
DECLARE rtype TEXT; ff_pos RECORD; tag_data RECORD; val TEXT; collection TEXT[] := '{}'::TEXT[]; BEGIN rtype := (vandelay.marc21_record_type( marc )).code; FOR ff_pos IN SELECT * FROM config.marc21_ff_pos_map WHERE fixed_field = ff AND rec_type = rtype ORDER BY tag DESC LOOP IF ff_pos.tag = 'ldr' THEN val := oils_xpath_string('//*[local-name()="leader"]', marc); IF val IS NOT NULL THEN val := SUBSTRING( val, ff_pos.start_pos + 1, ff_pos.length ); collection := collection || val; END IF; ELSE FOR tag_data IN SELECT value FROM UNNEST( oils_xpath( '//*[@tag="' || UPPER(ff_pos.tag) || '"]/text()', marc ) ) x(value) LOOP val := SUBSTRING( tag_data.value, ff_pos.start_pos + 1, ff_pos.length ); collection := collection || val; END LOOP; END IF; CONTINUE WHEN NOT use_default; CONTINUE WHEN ARRAY_UPPER(collection, 1) > 0; val := REPEAT( ff_pos.default_val, ff_pos.length ); collection := collection || val; END LOOP; RETURN collection; END;
Function: vandelay.marc21_physical_characteristics(marc text)
Returns: SET OF marc21_physical_characteristics
Language: PLPGSQL
DECLARE rowid INT := 0; _007 TEXT; ptype config.marc21_physical_characteristic_type_map%ROWTYPE; psf config.marc21_physical_characteristic_subfield_map%ROWTYPE; pval config.marc21_physical_characteristic_value_map%ROWTYPE; retval biblio.marc21_physical_characteristics%ROWTYPE; BEGIN FOR _007 IN SELECT oils_xpath_string('//*', value) FROM UNNEST(oils_xpath('//*[@tag="007"]', marc)) x(value) LOOP IF _007 IS NOT NULL AND _007 <> '' THEN SELECT * INTO ptype FROM config.marc21_physical_characteristic_type_map WHERE ptype_key = SUBSTRING( _007, 1, 1 ); IF ptype.ptype_key IS NOT NULL THEN FOR psf IN SELECT * FROM config.marc21_physical_characteristic_subfield_map WHERE ptype_key = ptype.ptype_key LOOP SELECT * INTO pval FROM config.marc21_physical_characteristic_value_map WHERE ptype_subfield = psf.id AND value = SUBSTRING( _007, psf.start_pos + 1, psf.length ); IF pval.id IS NOT NULL THEN rowid := rowid + 1; retval.id := rowid; retval.ptype := ptype.ptype_key; retval.subfield := psf.id; retval.value := pval.id; RETURN NEXT retval; END IF; END LOOP; END IF; END IF; END LOOP; RETURN; END;
Function: vandelay.marc21_record_type(marc text)
Returns: marc21_rec_type_map
Language: PLPGSQL
DECLARE ldr TEXT; tval TEXT; tval_rec RECORD; bval TEXT; bval_rec RECORD; retval config.marc21_rec_type_map%ROWTYPE; BEGIN ldr := oils_xpath_string( '//*[local-name()="leader"]', marc ); IF ldr IS NULL OR ldr = '' THEN SELECT * INTO retval FROM config.marc21_rec_type_map WHERE code = 'BKS'; RETURN retval; END IF; SELECT * INTO tval_rec FROM config.marc21_ff_pos_map WHERE fixed_field = 'Type' LIMIT 1; -- They're all the same SELECT * INTO bval_rec FROM config.marc21_ff_pos_map WHERE fixed_field = 'BLvl' LIMIT 1; -- They're all the same tval := SUBSTRING( ldr, tval_rec.start_pos + 1, tval_rec.length ); bval := SUBSTRING( ldr, bval_rec.start_pos + 1, bval_rec.length ); -- RAISE NOTICE 'type %, blvl %, ldr %', tval, bval, ldr; SELECT * INTO retval FROM config.marc21_rec_type_map WHERE type_val LIKE '%' || tval || '%' AND blvl_val LIKE '%' || bval || '%'; IF retval.code IS NULL THEN SELECT * INTO retval FROM config.marc21_rec_type_map WHERE code = 'BKS'; END IF; RETURN retval; END;
Function: vandelay.match_authority_record()
Returns: trigger
Language: PLPGSQL
DECLARE incoming_existing_id TEXT; test_result vandelay.match_set_test_result%ROWTYPE; tmp_rec BIGINT; match_set INT; BEGIN IF TG_OP IN ('INSERT','UPDATE') AND NEW.imported_as IS NOT NULL THEN RETURN NEW; END IF; DELETE FROM vandelay.authority_match WHERE queued_record = NEW.id; SELECT q.match_set INTO match_set FROM vandelay.authority_queue q WHERE q.id = NEW.queue; IF match_set IS NOT NULL THEN NEW.quality := vandelay.measure_auth_record_quality( NEW.marc, match_set ); END IF; -- Perfect matches on 901$c exit early with a match with high quality. incoming_existing_id := oils_xpath_string('//*[@tag="901"]/*[@code="c"][1]', NEW.marc); IF incoming_existing_id IS NOT NULL AND incoming_existing_id != '' THEN SELECT id INTO tmp_rec FROM authority.record_entry WHERE id = incoming_existing_id::bigint; IF tmp_rec IS NOT NULL THEN INSERT INTO vandelay.authority_match (queued_record, eg_record, match_score, quality) SELECT NEW.id, b.id, 9999, -- note: no match_set means quality==0 vandelay.measure_auth_record_quality( b.marc, match_set ) FROM authority.record_entry b WHERE id = incoming_existing_id::bigint; END IF; END IF; IF match_set IS NULL THEN RETURN NEW; END IF; FOR test_result IN SELECT * FROM vandelay.match_set_test_authxml(match_set, NEW.marc) LOOP INSERT INTO vandelay.authority_match ( queued_record, eg_record, match_score, quality ) SELECT NEW.id, test_result.record, test_result.quality, vandelay.measure_auth_record_quality( b.marc, match_set ) FROM authority.record_entry b WHERE id = test_result.record; END LOOP; RETURN NEW; END;
Function: vandelay.match_bib_record()
Returns: trigger
Language: PLPGSQL
DECLARE incoming_existing_id TEXT; test_result vandelay.match_set_test_result%ROWTYPE; tmp_rec BIGINT; match_set INT; match_bucket INT; BEGIN IF TG_OP IN ('INSERT','UPDATE') AND NEW.imported_as IS NOT NULL THEN RETURN NEW; END IF; DELETE FROM vandelay.bib_match WHERE queued_record = NEW.id; SELECT q.match_set INTO match_set FROM vandelay.bib_queue q WHERE q.id = NEW.queue; IF match_set IS NOT NULL THEN NEW.quality := vandelay.measure_record_quality( NEW.marc, match_set ); END IF; -- Perfect matches on 901$c exit early with a match with high quality. incoming_existing_id := oils_xpath_string('//*[@tag="901"]/*[@code="c"][1]', NEW.marc); IF incoming_existing_id IS NOT NULL AND incoming_existing_id != '' THEN SELECT id INTO tmp_rec FROM biblio.record_entry WHERE id = incoming_existing_id::bigint; IF tmp_rec IS NOT NULL THEN INSERT INTO vandelay.bib_match (queued_record, eg_record, match_score, quality) SELECT NEW.id, b.id, 9999, -- note: no match_set means quality==0 vandelay.measure_record_quality( b.marc, match_set ) FROM biblio.record_entry b WHERE id = incoming_existing_id::bigint; END IF; END IF; IF match_set IS NULL THEN RETURN NEW; END IF; SELECT q.match_bucket INTO match_bucket FROM vandelay.bib_queue q WHERE q.id = NEW.queue; FOR test_result IN SELECT * FROM vandelay.match_set_test_marcxml(match_set, NEW.marc, match_bucket) LOOP INSERT INTO vandelay.bib_match ( queued_record, eg_record, match_score, quality ) SELECT NEW.id, test_result.record, test_result.quality, vandelay.measure_record_quality( b.marc, match_set ) FROM biblio.record_entry b WHERE id = test_result.record; END LOOP; RETURN NEW; END;
Function: vandelay.match_set_test_authxml(record_xml integer, match_set_id text)
Returns: SET OF match_set_test_result
Language: PLPGSQL
DECLARE tags_rstore HSTORE; heading TEXT; coal TEXT; joins TEXT; query_ TEXT; wq TEXT; qvalue INTEGER; rec RECORD; BEGIN tags_rstore := vandelay.flatten_marc_hstore(record_xml); SELECT normalize_heading INTO heading FROM authority.normalize_heading(record_xml); CREATE TEMPORARY TABLE _vandelay_tmp_qrows (q INTEGER); CREATE TEMPORARY TABLE _vandelay_tmp_jrows (j TEXT); -- generate the where clause and return that directly (into wq), and as -- a side-effect, populate the _vandelay_tmp_[qj]rows tables. wq := vandelay.get_expr_from_match_set( match_set_id, tags_rstore, heading); query_ := 'SELECT DISTINCT(record), '; -- qrows table is for the quality bits we add to the SELECT clause SELECT STRING_AGG( 'COALESCE(n' || q::TEXT || '.quality, 0)', ' + ' ) INTO coal FROM _vandelay_tmp_qrows; -- our query string so far is the SELECT clause and the inital FROM. -- no JOINs yet nor the WHERE clause query_ := query_ || coal || ' AS quality ' || E'\n'; -- jrows table is for the joins we must make (and the real text conditions) SELECT STRING_AGG(j, E'\n') INTO joins FROM _vandelay_tmp_jrows; -- add those joins and the where clause to our query. query_ := query_ || joins || E'\n'; query_ := query_ || 'JOIN authority.record_entry are ON (are.id = record) ' || 'WHERE ' || wq || ' AND not are.deleted'; -- this will return rows of record,quality FOR rec IN EXECUTE query_ USING tags_rstore LOOP RETURN NEXT rec; END LOOP; DROP TABLE _vandelay_tmp_qrows; DROP TABLE _vandelay_tmp_jrows; RETURN; END;
Function: vandelay.match_set_test_marcxml(bucket_id integer, record_xml text, match_set_id integer)
Returns: SET OF match_set_test_result
Language: PLPGSQL
DECLARE tags_rstore HSTORE; svf_rstore HSTORE; coal TEXT; joins TEXT; query_ TEXT; wq TEXT; qvalue INTEGER; rec RECORD; BEGIN tags_rstore := vandelay.flatten_marc_hstore(record_xml); svf_rstore := vandelay.extract_rec_attrs(record_xml); CREATE TEMPORARY TABLE _vandelay_tmp_qrows (q INTEGER); CREATE TEMPORARY TABLE _vandelay_tmp_jrows (j TEXT); -- generate the where clause and return that directly (into wq), and as -- a side-effect, populate the _vandelay_tmp_[qj]rows tables. wq := vandelay.get_expr_from_match_set(match_set_id, tags_rstore); query_ := 'SELECT DISTINCT(record), '; -- qrows table is for the quality bits we add to the SELECT clause SELECT STRING_AGG( 'COALESCE(n' || q::TEXT || '.quality, 0)', ' + ' ) INTO coal FROM _vandelay_tmp_qrows; -- our query string so far is the SELECT clause and the inital FROM. -- no JOINs yet nor the WHERE clause query_ := query_ || coal || ' AS quality ' || E'\n'; -- jrows table is for the joins we must make (and the real text conditions) SELECT STRING_AGG(j, E'\n') INTO joins FROM _vandelay_tmp_jrows; -- add those joins and the where clause to our query. query_ := query_ || joins || E'\n'; -- join the record bucket IF bucket_id IS NOT NULL THEN query_ := query_ || 'JOIN container.biblio_record_entry_bucket_item ' || 'brebi ON (brebi.target_biblio_record_entry = record ' || 'AND brebi.bucket = ' || bucket_id || E')\n'; END IF; query_ := query_ || 'JOIN biblio.record_entry bre ON (bre.id = record) ' || 'WHERE ' || wq || ' AND not bre.deleted'; -- this will return rows of record,quality FOR rec IN EXECUTE query_ USING tags_rstore, svf_rstore LOOP RETURN NEXT rec; END LOOP; DROP TABLE _vandelay_tmp_qrows; DROP TABLE _vandelay_tmp_jrows; RETURN; END;
Function: vandelay.measure_auth_record_quality(match_set_id text, xml integer)
Returns: integer
Language: PLPGSQL
DECLARE out_q INT := 0; rvalue TEXT; test vandelay.match_set_quality%ROWTYPE; BEGIN FOR test IN SELECT * FROM vandelay.match_set_quality WHERE match_set = match_set_id LOOP IF test.tag IS NOT NULL THEN FOR rvalue IN SELECT value FROM vandelay.flatten_marc( xml ) WHERE tag = test.tag AND subfield = test.subfield LOOP IF test.value = rvalue THEN out_q := out_q + test.quality; END IF; END LOOP; END IF; END LOOP; RETURN out_q; END;
Function: vandelay.measure_record_quality(match_set_id text, xml integer)
Returns: integer
Language: PLPGSQL
DECLARE out_q INT := 0; rvalue TEXT; test vandelay.match_set_quality%ROWTYPE; BEGIN FOR test IN SELECT * FROM vandelay.match_set_quality WHERE match_set = match_set_id LOOP IF test.tag IS NOT NULL THEN FOR rvalue IN SELECT value FROM vandelay.flatten_marc( xml ) WHERE tag = test.tag AND subfield = test.subfield LOOP IF test.value = rvalue THEN out_q := out_q + test.quality; END IF; END LOOP; ELSE IF test.value = vandelay.extract_rec_attrs(xml, ARRAY[test.svf]) -> test.svf THEN out_q := out_q + test.quality; END IF; END IF; END LOOP; RETURN out_q; END;
Function: vandelay.merge_record_xml(strip_rule text, replace_preserve_rule text, add_rule text, source_xml text, target_xml text)
Returns: text
Language: SQL
SELECT vandelay.replace_field( vandelay.add_field( vandelay.strip_field( $1, $5) , $2, $3 ), $2, $4);
Function: vandelay.merge_record_xml(template_marc text, target_marc text)
Returns: text
Language: PLPGSQL
DECLARE dyn_profile vandelay.compile_profile%ROWTYPE; replace_rule TEXT; tmp_marc TEXT; trgt_marc TEXT; tmpl_marc TEXT; match_count INT; BEGIN IF target_marc IS NULL OR template_marc IS NULL THEN -- RAISE NOTICE 'no marc for target or template record'; RETURN NULL; END IF; dyn_profile := vandelay.compile_profile( template_marc ); IF dyn_profile.replace_rule <> '' AND dyn_profile.preserve_rule <> '' THEN -- RAISE NOTICE 'both replace [%] and preserve [%] specified', dyn_profile.replace_rule, dyn_profile.preserve_rule; RETURN NULL; END IF; IF dyn_profile.replace_rule = '' AND dyn_profile.preserve_rule = '' AND dyn_profile.add_rule = '' AND dyn_profile.strip_rule = '' THEN --Since we have nothing to do, just return what we were given. RETURN target_marc; ELSIF dyn_profile.replace_rule <> '' THEN trgt_marc = target_marc; tmpl_marc = template_marc; replace_rule = dyn_profile.replace_rule; ELSE tmp_marc = target_marc; trgt_marc = template_marc; tmpl_marc = tmp_marc; replace_rule = dyn_profile.preserve_rule; END IF; RETURN vandelay.merge_record_xml( trgt_marc, tmpl_marc, dyn_profile.add_rule, replace_rule, dyn_profile.strip_rule ); END;
Function: vandelay.merge_record_xml_using_profile(merge_profile_id text, existing_marc text, incoming_marc bigint)
Returns: text
Language: PLPGSQL
DECLARE merge_profile vandelay.merge_profile%ROWTYPE; dyn_profile vandelay.compile_profile%ROWTYPE; target_marc TEXT; source_marc TEXT; replace_rule TEXT; match_count INT; BEGIN IF existing_marc IS NULL OR incoming_marc IS NULL THEN -- RAISE NOTICE 'no marc for source or target records'; RETURN NULL; END IF; IF merge_profile_id IS NOT NULL THEN SELECT * INTO merge_profile FROM vandelay.merge_profile WHERE id = merge_profile_id; IF FOUND THEN dyn_profile.add_rule := COALESCE(merge_profile.add_spec,''); dyn_profile.strip_rule := COALESCE(merge_profile.strip_spec,''); dyn_profile.replace_rule := COALESCE(merge_profile.replace_spec,''); dyn_profile.preserve_rule := COALESCE(merge_profile.preserve_spec,''); ELSE -- RAISE NOTICE 'merge profile not found'; RETURN NULL; END IF; ELSE -- RAISE NOTICE 'no merge profile specified'; RETURN NULL; END IF; IF dyn_profile.replace_rule <> '' AND dyn_profile.preserve_rule <> '' THEN -- RAISE NOTICE 'both replace [%] and preserve [%] specified', dyn_profile.replace_rule, dyn_profile.preserve_rule; RETURN NULL; END IF; IF dyn_profile.replace_rule = '' AND dyn_profile.preserve_rule = '' AND dyn_profile.add_rule = '' AND dyn_profile.strip_rule = '' THEN -- Since we have nothing to do, just return a target record as is RETURN existing_marc; ELSIF dyn_profile.preserve_rule <> '' THEN source_marc = existing_marc; target_marc = incoming_marc; replace_rule = dyn_profile.preserve_rule; ELSE source_marc = incoming_marc; target_marc = existing_marc; replace_rule = dyn_profile.replace_rule; END IF; RETURN vandelay.merge_record_xml( target_marc, source_marc, dyn_profile.add_rule, replace_rule, dyn_profile.strip_rule ); END;
Function: vandelay.overlay_authority_record(merge_profile_id bigint, eg_id bigint, import_id integer)
Returns: boolean
Language: PLPGSQL
DECLARE merge_profile vandelay.merge_profile%ROWTYPE; dyn_profile vandelay.compile_profile%ROWTYPE; editor_string TEXT; new_editor INT; new_edit_date TIMESTAMPTZ; source_marc TEXT; target_marc TEXT; eg_marc_row authority.record_entry%ROWTYPE; eg_marc TEXT; v_marc TEXT; replace_rule TEXT; match_count INT; update_query TEXT; BEGIN SELECT * INTO eg_marc_row FROM authority.record_entry b JOIN vandelay.authority_match m ON (m.eg_record = b.id AND m.queued_record = import_id) LIMIT 1; SELECT q.marc INTO v_marc FROM vandelay.queued_record q JOIN vandelay.authority_match m ON (m.queued_record = q.id AND q.id = import_id) LIMIT 1; eg_marc := eg_marc_row.marc; IF eg_marc IS NULL OR v_marc IS NULL THEN -- RAISE NOTICE 'no marc for vandelay or authority record'; RETURN FALSE; END IF; -- Extract the editor string before any modification to the vandelay -- MARC occur. editor_string := (oils_xpath('//*[@tag="905"]/*[@code="u"]/text()',v_marc))[1]; -- If an editor value can be found, update the authority record -- editor and edit_date values. IF editor_string IS NOT NULL AND editor_string <> '' THEN -- Vandelay.pm sets the value to 'usrname' when needed. SELECT id INTO new_editor FROM actor.usr WHERE usrname = editor_string; IF new_editor IS NULL THEN SELECT usr INTO new_editor FROM actor.card WHERE barcode = editor_string; END IF; IF new_editor IS NOT NULL THEN new_edit_date := NOW(); ELSE -- No valid editor, use current values new_editor = eg_marc_row.editor; new_edit_date = eg_marc_row.edit_date; END IF; ELSE new_editor = eg_marc_row.editor; new_edit_date = eg_marc_row.edit_date; END IF; dyn_profile := vandelay.compile_profile( v_marc ); IF merge_profile_id IS NOT NULL THEN SELECT * INTO merge_profile FROM vandelay.merge_profile WHERE id = merge_profile_id; IF FOUND THEN dyn_profile.add_rule := BTRIM( dyn_profile.add_rule || ',' || COALESCE(merge_profile.add_spec,''), ','); dyn_profile.strip_rule := BTRIM( dyn_profile.strip_rule || ',' || COALESCE(merge_profile.strip_spec,''), ','); dyn_profile.replace_rule := BTRIM( dyn_profile.replace_rule || ',' || COALESCE(merge_profile.replace_spec,''), ','); dyn_profile.preserve_rule := BTRIM( dyn_profile.preserve_rule || ',' || COALESCE(merge_profile.preserve_spec,''), ','); END IF; END IF; IF dyn_profile.replace_rule <> '' AND dyn_profile.preserve_rule <> '' THEN -- RAISE NOTICE 'both replace [%] and preserve [%] specified', dyn_profile.replace_rule, dyn_profile.preserve_rule; RETURN FALSE; END IF; IF dyn_profile.replace_rule = '' AND dyn_profile.preserve_rule = '' AND dyn_profile.add_rule = '' AND dyn_profile.strip_rule = '' THEN --Since we have nothing to do, just return a NOOP "we did it" RETURN TRUE; ELSIF dyn_profile.replace_rule <> '' THEN source_marc = v_marc; target_marc = eg_marc; replace_rule = dyn_profile.replace_rule; ELSE source_marc = eg_marc; target_marc = v_marc; replace_rule = dyn_profile.preserve_rule; END IF; UPDATE authority.record_entry SET marc = vandelay.merge_record_xml( target_marc, source_marc, dyn_profile.add_rule, replace_rule, dyn_profile.strip_rule ), editor = new_editor, edit_date = new_edit_date WHERE id = eg_id; IF NOT FOUND THEN -- Import/merge failed. Nothing left to do. RETURN FALSE; END IF; -- Authority record successfully merged / imported. -- Update the vandelay record to show the successful import. UPDATE vandelay.queued_authority_record SET imported_as = eg_id, import_time = NOW() WHERE id = import_id; RETURN TRUE; END;
Function: vandelay.overlay_bib_record(merge_profile_id bigint, eg_id bigint, import_id integer)
Returns: boolean
Language: PLPGSQL
DECLARE editor_string TEXT; editor_id INT; v_marc TEXT; v_bib_source INT; update_fields TEXT[]; update_query TEXT; update_bib_source BOOL; update_bib_editor BOOL; BEGIN SELECT q.marc, q.bib_source INTO v_marc, v_bib_source FROM vandelay.queued_bib_record q JOIN vandelay.bib_match m ON (m.queued_record = q.id AND q.id = import_id) LIMIT 1; IF v_marc IS NULL THEN -- RAISE NOTICE 'no marc for vandelay or bib record'; RETURN FALSE; END IF; IF NOT vandelay.template_overlay_bib_record( v_marc, eg_id, merge_profile_id) THEN -- no update happened, get outta here. RETURN FALSE; END IF; UPDATE vandelay.queued_bib_record SET imported_as = eg_id, import_time = NOW() WHERE id = import_id; SELECT q.update_bib_source INTO update_bib_source FROM vandelay.merge_profile q where q.id = merge_profile_Id; IF update_bib_source AND v_bib_source IS NOT NULL THEN update_fields := ARRAY_APPEND(update_fields, 'source = ' || v_bib_source); END IF; SELECT q.update_bib_editor INTO update_bib_editor FROM vandelay.merge_profile q where q.id = merge_profile_Id; IF update_bib_editor THEN editor_string := (oils_xpath('//*[@tag="905"]/*[@code="u"]/text()',v_marc))[1]; IF editor_string IS NOT NULL AND editor_string <> '' THEN SELECT usr INTO editor_id FROM actor.card WHERE barcode = editor_string; IF editor_id IS NULL THEN SELECT id INTO editor_id FROM actor.usr WHERE usrname = editor_string; END IF; IF editor_id IS NOT NULL THEN --only update the edit date if we have a valid editor update_fields := ARRAY_APPEND( update_fields, 'editor = ' || editor_id || ', edit_date = NOW()'); END IF; END IF; END IF; IF ARRAY_LENGTH(update_fields, 1) > 0 THEN update_query := 'UPDATE biblio.record_entry SET ' || ARRAY_TO_STRING(update_fields, ',') || ' WHERE id = ' || eg_id || ';'; EXECUTE update_query; END IF; RETURN TRUE; END;
Function: vandelay.replace_field(field text, source_xml text, target_xml text)
Returns: text
Language: PLPERLU
use strict; use MARC::Record; use MARC::Field; use MARC::File::XML (BinaryEncoding => 'UTF-8'); use MARC::Charset; MARC::Charset->assume_unicode(1); my $target_xml = shift; my $source_xml = shift; my $field_spec = shift; my $target_r = MARC::Record->new_from_xml($target_xml); my $source_r = MARC::Record->new_from_xml($source_xml); return $target_xml unless $target_r && $source_r; # Extract the field_spec components into MARC tags, subfields, # and regex matches. Copied wholesale from vandelay.strip_field() my @field_list = split(',', $field_spec); my %fields; for my $f (@field_list) { $f =~ s/^\s*//; $f =~ s/\s*$//; if ($f =~ /^(.{3})(\w*)(?:\[([^]]*)\])?$/) { my $field = $1; $field =~ s/\s+//; my $sf = $2; $sf =~ s/\s+//; my $match = $3; $match =~ s/^\s*//; $match =~ s/\s*$//; $fields{$field} = { sf => [ split('', $sf) ] }; if ($match) { my ($msf,$mre) = split('~', $match); if (length($msf) > 0 and length($mre) > 0) { $msf =~ s/^\s*//; $msf =~ s/\s*$//; $mre =~ s/^\s*//; $mre =~ s/\s*$//; $fields{$field}{match} = { sf => $msf, re => qr/$mre/ }; } } } } # Returns a flat list of subfield (code, value, code, value, ...) # suitable for adding to a MARC::Field. sub generate_replacement_subfields { my ($source_field, $target_field, @controlled_subfields) = @_; # Performing a wholesale field replacment. # Use the entire source field as-is. return map {$_->[0], $_->[1]} $source_field->subfields unless @controlled_subfields; my @new_subfields; # Iterate over all target field subfields: # 1. Keep uncontrolled subfields as is. # 2. Replace values for controlled subfields when a # replacement value exists on the source record. # 3. Delete values for controlled subfields when no # replacement value exists on the source record. for my $target_sf ($target_field->subfields) { my $subfield = $target_sf->[0]; my $target_val = $target_sf->[1]; if (grep {$_ eq $subfield} @controlled_subfields) { if (my $source_val = $source_field->subfield($subfield)) { # We have a replacement value push(@new_subfields, $subfield, $source_val); } else { # no replacement value for controlled subfield, drop it. } } else { # Field is not controlled. Copy it over as-is. push(@new_subfields, $subfield, $target_val); } } # Iterate over all subfields in the source field and back-fill # any values that exist only in the source field. Insert these # subfields in the same relative position they exist in the # source field. my @seen_subfields; for my $source_sf ($source_field->subfields) { my $subfield = $source_sf->[0]; my $source_val = $source_sf->[1]; push(@seen_subfields, $subfield); # target field already contains this subfield, # so it would have been addressed above. next if $target_field->subfield($subfield); # Ignore uncontrolled subfields. next unless grep {$_ eq $subfield} @controlled_subfields; # Adding a new subfield. Find its relative position and add # it to the list under construction. Work backwards from # the list of already seen subfields to find the best slot. my $done = 0; for my $seen_sf (reverse(@seen_subfields)) { my $idx = @new_subfields; for my $new_sf (reverse(@new_subfields)) { $idx--; next if $idx % 2 == 1; # sf codes are in the even slots if ($new_subfields[$idx] eq $seen_sf) { splice(@new_subfields, $idx + 2, 0, $subfield, $source_val); $done = 1; last; } } last if $done; } # if no slot was found, add to the end of the list. push(@new_subfields, $subfield, $source_val) unless $done; } return @new_subfields; } # MARC tag loop for my $f (keys %fields) { my $tag_idx = -1; for my $target_field ($target_r->field($f)) { # field spec contains a regex for this field. Confirm field on # target record matches the specified regex before replacing. if (exists($fields{$f}{match})) { next unless (grep { $_ =~ $fields{$f}{match}{re} } $target_field->subfield($fields{$f}{match}{sf})); } my @new_subfields; my @controlled_subfields = @{$fields{$f}{sf}}; # If the target record has multiple matching bib fields, # replace them from matching fields on the source record # in a predictable order to avoid replacing with them with # same source field repeatedly. my @source_fields = $source_r->field($f); my $source_field = $source_fields[++$tag_idx]; if (!$source_field && @controlled_subfields) { # When there are more target fields than source fields # and we are replacing values for subfields and not # performing wholesale field replacment, use the last # available source field as the input for all remaining # target fields. $source_field = $source_fields[$#source_fields]; } if (!$source_field) { # No source field exists. Delete all affected target # data. This is a little bit counterintuitive, but is # backwards compatible with the previous version of this # function which first deleted all affected data, then # replaced values where possible. if (@controlled_subfields) { $target_field->delete_subfield($_) for @controlled_subfields; } else { $target_r->delete_field($target_field); } next; } my @new_subfields = generate_replacement_subfields( $source_field, $target_field, @controlled_subfields); # Build the replacement field from scratch. my $replacement_field = MARC::Field->new( $target_field->tag, $target_field->indicator(1), $target_field->indicator(2), @new_subfields ); $target_field->replace_with($replacement_field); } } $target_xml = $target_r->as_xml_record; $target_xml =~ s/^<\?.+?\?>$//mo; $target_xml =~ s/\n//sgo; $target_xml =~ s/>\s+</></sgo; return $target_xml;
Function: vandelay.strip_field(field text, xml text)
Returns: text
Language: PLPERLU
use MARC::Record; use MARC::File::XML (BinaryEncoding => 'UTF-8'); use MARC::Charset; use strict; MARC::Charset->assume_unicode(1); my $xml = shift; my $r = MARC::Record->new_from_xml( $xml ); return $xml unless ($r); my $field_spec = shift; my @field_list = split(',', $field_spec); my %fields; for my $f (@field_list) { $f =~ s/^\s*//; $f =~ s/\s*$//; if ($f =~ /^(.{3})(\w*)(?:\[([^]]*)\])?$/) { my $field = $1; $field =~ s/\s+//; my $sf = $2; $sf =~ s/\s+//; my $matches = $3; $matches =~ s/^\s*//; $matches =~ s/\s*$//; $fields{$field} = { sf => [ split('', $sf) ] }; if ($matches) { for my $match (split('&&', $matches)) { $match =~ s/^\s*//; $match =~ s/\s*$//; my ($msf,$mre) = split('~', $match); if (length($msf) > 0 and length($mre) > 0) { $msf =~ s/^\s*//; $msf =~ s/\s*$//; $mre =~ s/^\s*//; $mre =~ s/\s*$//; $fields{$field}{match}{$msf} = qr/$mre/; } } } } } for my $f ( keys %fields) { for my $to_field ($r->field( $f )) { if (exists($fields{$f}{match})) { my @match_list = grep { $to_field->subfield($_) =~ $fields{$f}{match}{$_} } keys %{$fields{$f}{match}}; next unless (scalar(@match_list) == scalar(keys %{$fields{$f}{match}})); } if ( @{$fields{$f}{sf}} ) { $to_field->delete_subfield(code => $fields{$f}{sf}); } else { $r->delete_field( $to_field ); } } } $xml = $r->as_xml_record; $xml =~ s/^<\?.+?\?>$//mo; $xml =~ s/\n//sgo; $xml =~ s/>\s+</></sgo; return $xml;
Function: vandelay.template_overlay_bib_record(eg_id text, v_marc bigint)
Returns: boolean
Language: SQL
SELECT vandelay.template_overlay_bib_record( $1, $2, NULL);
Function: vandelay.template_overlay_bib_record(merge_profile_id text, eg_id bigint, v_marc integer)
Returns: boolean
Language: PLPGSQL
DECLARE merge_profile vandelay.merge_profile%ROWTYPE; dyn_profile vandelay.compile_profile%ROWTYPE; editor_string TEXT; editor_id INT; source_marc TEXT; target_marc TEXT; eg_marc TEXT; replace_rule TEXT; match_count INT; BEGIN SELECT b.marc INTO eg_marc FROM biblio.record_entry b WHERE b.id = eg_id LIMIT 1; IF eg_marc IS NULL OR v_marc IS NULL THEN -- RAISE NOTICE 'no marc for template or bib record'; RETURN FALSE; END IF; dyn_profile := vandelay.compile_profile( v_marc ); IF merge_profile_id IS NOT NULL THEN SELECT * INTO merge_profile FROM vandelay.merge_profile WHERE id = merge_profile_id; IF FOUND THEN dyn_profile.add_rule := BTRIM( dyn_profile.add_rule || ',' || COALESCE(merge_profile.add_spec,''), ','); dyn_profile.strip_rule := BTRIM( dyn_profile.strip_rule || ',' || COALESCE(merge_profile.strip_spec,''), ','); dyn_profile.replace_rule := BTRIM( dyn_profile.replace_rule || ',' || COALESCE(merge_profile.replace_spec,''), ','); dyn_profile.preserve_rule := BTRIM( dyn_profile.preserve_rule || ',' || COALESCE(merge_profile.preserve_spec,''), ','); END IF; END IF; IF dyn_profile.replace_rule <> '' AND dyn_profile.preserve_rule <> '' THEN -- RAISE NOTICE 'both replace [%] and preserve [%] specified', dyn_profile.replace_rule, dyn_profile.preserve_rule; RETURN FALSE; END IF; IF dyn_profile.replace_rule = '' AND dyn_profile.preserve_rule = '' AND dyn_profile.add_rule = '' AND dyn_profile.strip_rule = '' THEN --Since we have nothing to do, just return a NOOP "we did it" RETURN TRUE; ELSIF dyn_profile.replace_rule <> '' THEN source_marc = v_marc; target_marc = eg_marc; replace_rule = dyn_profile.replace_rule; ELSE source_marc = eg_marc; target_marc = v_marc; replace_rule = dyn_profile.preserve_rule; END IF; UPDATE biblio.record_entry SET marc = vandelay.merge_record_xml( target_marc, source_marc, dyn_profile.add_rule, replace_rule, dyn_profile.strip_rule ) WHERE id = eg_id; IF NOT FOUND THEN -- RAISE NOTICE 'update of biblio.record_entry failed'; RETURN FALSE; END IF; RETURN TRUE; END;
Generated by PostgreSQL Autodoc