= Процедури = === Процедура 1: Додавање третман на археолошки предмет (add_treatment) === 1. **Намена:** Процедурата `add_treatment` е наменета за евидентирање на нов конзерваторски или реставраторски третман над археолошки предмет. Нејзината основна цел е да обезбеди контролирано внесување на третмани, при што секој третман се поврзува со конкретен предмет (`object_id`) и автоматски добива датум на внесување. 2. **Случај на употреба:** Во рамки на системот за управување со културно наследство, археолошките предмети често поминуваат низ повеќе конзерваторски интервенции (чистење, стабилизација, реконструкција, лабораториска обработка и слично). Наместо рачно внесување на записи во табелата `Treatments`, процедурата обезбедува стандардизиран начин за евиденција на интервенциите. 3. **Причина за употреба на процедура:** Избрана е процедура наместо директен `INSERT` бидејќи постои потреба од дополнителна бизнис логика и валидација пред внесување на третман. Процедурата ја користи функцијата `is_object_available(p_object_id)` со цел да се провери дали предметот е достапен за третман. Без оваа проверка би било возможно да се внесе третман за предмет кој: * не постои * има статус што не дозволува третман * не е достапен за обработка 4. **Имплементација:** Процедурата прима: * `p_object_id` – идентификатор на предметот * `p_desc` – опис на третманот Пред внесување се повикува: {{{ IF NOT is_object_available(p_object_id) }}} Доколку предметот не е достапен, процедурата прекинува со грешка: {{{ RAISE EXCEPTION 'Објектот не е достапен за третман'; }}} Доколку условот е исполнет, се креира запис во табелата `Treatments`, а датумот автоматски се поставува преку: {{{ CURRENT_DATE }}} 5. **Логика на работа:** Оваа процедура имплементира контрола на процесот на конзервација. Во реален музејски или археолошки контекст, не секој предмет може веднаш да биде обработуван – некои предмети можат да бидат веќе во процес на реставрација, дел од изложба, во транспорт или привремено недостапни. Со ова се обезбедува конзистентност во евиденцијата на третмани и се спречуваат нелогични операции. 6. **Пример на употреба:** {{{ CALL add_treatment( 804822, 'Чистење' ); }}} 7. **Заклучок:** Процедурата `add_treatment` претставува важен дел од конзерваторскиот workflow во системот. Таа овозможува сигурна евиденција на реставраторски активности, спречува внесување третмани врз недостапни предмети и обезбедува доследна документација на интервенциите врз културното наследство. === Процедура 2: Барање пристап за истражување (request_access) === 1. **Намена:** Процедурата `request_access` е наменета за креирање ново барање за истражувачки пристап до конкретен археолошки предмет. Нејзината главна цел е да го моделира процесот на институционално одобрување на пристап до чувствителни археолошки информации. 2. **Случај на употреба:** Во реален систем за културно наследство, не секој корисник има директен пристап до сите предмети. Истражувачи, археолози и надворешни институции мора прво да поднесат барање за пристап, кое потоа може да биде одобрено или одбиено од институцијата која управува со предметот. 3. **Причина за употреба на процедура:** Процедурата е воведена со цел да се централизира процесот на поднесување барања за пристап. Наместо секој корисник директно да внесува записи во `Researcher_Access`, процедурата: * автоматски поставува датум на барањето * автоматски поставува статус „Во обработка“ * гарантира стандардизиран процес на внес 4. **Имплементација:** Процедурата прима: * `p_user_id` * `p_object_id` * `p_institution_id` При внесување автоматски се поставува: {{{ CURRENT_DATE }}} како датум на барање, а статусот автоматски добива вредност: {{{ 7 -- во обработка }}} со што новото барање не може веднаш да биде одобрено. 5. **Логика на работа:** Оваа процедура ја имплементира институционалната контрола на пристап до археолошки предмети. Во реална средина, дел од артефактите може да бидат чувствителни, недостапни за јавноста или во процес на научна обработка. Со користење на оваа процедура се обезбедува: * следење на кој корисник побарал пристап * следење на институцијата од која доаѓа барањето * централизирана контрола на одобрување 6. **Пример на употреба:** {{{ CALL request_access( 10, 804822, 1 ); }}} 7. **Заклучок:** `request_access` претставува важен механизам за контрола на истражувачки пристап и обезбедува правилна имплементација на безбедносната политика на системот. === Процедура 3: Додавање автор во публикација (add_author_to_publication) === 1. **Намена:** Процедурата `add_author_to_publication` е наменета за поврзување на автор со научна публикација. 2. **Случај на употреба:** Во археолошките и научните истражувања, една публикација често има повеќе автори, а еден автор може да учествува во повеќе публикации. Оваа M:N релација е реализирана преку табелата `Publication_Authors`. 3. **Причина за употреба на процедура:** Избрана е процедура бидејќи е потребна дополнителна проверка за спречување дупликати. Пред внесување се проверува: {{{ IF EXISTS ( SELECT 1 FROM Publication_Authors ) }}} со што се спречува ист автор повеќепати да биде поврзан со истата публикација. 4. **Имплементација:** Процедурата прима: * `p_publication_id` * `p_author_id` Доколку авторот веќе постои во публикацијата: {{{ RAISE NOTICE 'Авторот веќе постои'; }}} во спротивно се врши внес. 5. **Логика на работа:** Оваа процедура обезбедува точна научна евиденција и спречува логички неконзистентни записи. 6. **Пример на употреба:** {{{ CALL add_author_to_publication( 50, 12 ); }}} 7. **Заклучок:** Процедурата овозможува конзистентна и точна евиденција на научно авторство, што е особено важно кај академски публикации и археолошка документација. === Процедура 4: Додавање нов археолошки предмет (add_new_object) === 1. **Намена:** Процедурата `add_new_object` е наменета за евидентирање нов археолошки предмет во системот. 2. **Случај на употреба:** При откривање на нов предмет на археолошки локалитет, потребно е негово иницијално внесување во базата, заедно со инвентарен број, локалитет, статус и корисникот кој го пронашол. 3. **Причина за употреба на процедура:** Избрана е процедура за да се централизира процесот на иницијална регистрација и да се избегне нецелосен внес на податоци. 4. **Имплементација:** Процедурата прима: * инвентарен број * наслов * статус * локалитет * корисник кој го пронашол предметот и директно внесува запис во `Objects`. 5. **Логика на работа:** Оваа процедура ја моделира реалната археолошка документација, каде секој предмет мора да има основни метаподатоци веднаш по неговото пронаоѓање. 6. **Пример на употреба:** {{{ CALL add_new_object( 'INV-2025-001', 'Керамичка вазна', 1, 10, 3 ); }}} 7. **Заклучок:** `add_new_object` овозможува конзистентен и стандарден процес на регистрација на нови археолошки предмети. === Процедура 5: Целосна каталогизација на предмет (catalog_object) === 1. **Намена:** Процедурата `catalog_object` е наменета за целосна каталогизација на археолошки предмет. 2. **Случај на употреба:** По иницијално внесување, предметите треба да добијат култура, категорија и материјал. Бидејќи овие информации се распоредени во повеќе табели, процесот би барал повеќе рачни `INSERT` операции. 3. **Причина за употреба на процедура:** Избрана е процедура бидејќи процесот бара координиран внес во повеќе табели: * `Objects` * `Object_Classification` * `Materials_Objects` 4. **Имплементација:** Најпрво се внесува предметот во `Objects`. Потоа преку: {{{ RETURNING object_id INTO v_object_id }}} се зачувува ID-то на новокреираниот предмет. Потоа автоматски се креираат записи во: * `Object_Classification` * `Materials_Objects` 5. **Логика на работа:** Оваа процедура ја моделира реалната каталогизација на археолошки предмет, каде објектот не е само физички запис, туку мора да биде класифициран според култура, категорија и материјал. 6. **Пример на употреба:** {{{ CALL catalog_object( 'INV-2025-021', 'Монета', 1, 3, 8, 2, 5, 1 ); }}} 7. **Заклучок:** `catalog_object` претставува централен механизам за каталогизација во системот, кој обезбедува конзистентност, автоматизација и намалување на човечки грешки при внес на археолошки податоци. = Тригери = === Тригер 1: Валидација на хиерархија на фрагменти (trg_fragment_check) === 1. **Намена:** Тригерот `trg_fragment_check` е наменет за автоматска валидација на записите во табелата `Fragments`. Неговата главна цел е да спречи внесување или ажурирање на фрагмент кој истовремено е директно поврзан со археолошки предмет (`object_id`) и со друг фрагмент (`parent_fragment_id`). 2. **Случај на употреба:** Во системот за управување со културно-археолошко наследство, фрагментите имаат важна улога затоа што претставуваат делови од артефакти, остатоци од предмети или под-фрагменти кои се пронајдени на локалитет. Поради тоа, секој фрагмент мора да има јасна логичка припадност. Фрагментот може: * директно да припаѓа на археолошки предмет преку `object_id` * да биде дел од друг фрагмент преку `parent_fragment_id` Но не смее истовремено да припаѓа и на предмет и на друг фрагмент, бидејќи тоа би создало нејасна и двојна хиерархија. 3. **Причина за избор на тригер:** Овој тригер е избран затоа што се работи за доменско правило кое мора да се провери автоматски пред секој внес или ажурирање. Иако во табелата `Fragments` постои и `CHECK` ограничување за ова правило, тригерот дополнително овозможува појасна контрола и експлицитна порака за грешка. Со ова се добива подобра разбирливост при тестирање и при работа со апликацијата, бидејќи корисникот добива конкретна порака: {{{ Фрагмент не може да има и object и parent }}} 4. **Имплементација:** Тригер функцијата е: {{{ CREATE OR REPLACE FUNCTION trg_fragment_validation() RETURNS TRIGGER AS $$ BEGIN IF NEW.object_id IS NOT NULL AND NEW.parent_fragment_id IS NOT NULL THEN RAISE EXCEPTION 'Фрагмент не може да има и object и parent'; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; }}} Тригерот се активира: {{{ CREATE TRIGGER trg_fragment_check BEFORE INSERT OR UPDATE ON Fragments FOR EACH ROW EXECUTE FUNCTION trg_fragment_validation(); }}} 5. **Логика на работа:** Тригерот се извршува пред секој `INSERT` или `UPDATE` врз табелата `Fragments`. Тој ја проверува новата вредност која треба да се внесе или ажурира преку `NEW`. Доколку и `NEW.object_id` и `NEW.parent_fragment_id` имаат вредност различна од `NULL`, записот се одбива и се фрла исклучок. Ова значи дека базата не дозволува фрагментот да има двојна припадност. 6. **Бизнис логика:** Овој тригер ја имплементира логиката за зачувување на археолошкиот контекст на фрагментите. Во реална археолошка евиденција, важно е точно да се знае дали еден фрагмент е директен дел од предмет или е под-фрагмент од друг фрагмент. Ако ова правило не постои, би можело да се случи ист фрагмент да биде прикажан во две различни структури, што би предизвикало погрешни извештаи, неточна реконструкција на предметите и неконзистентна научна документација. 7. **Пример на неправилен внес:** {{{ INSERT INTO Fragments (object_id, parent_fragment_id, status_id) VALUES (1, 2, 1); }}} Овој внес се одбива затоа што фрагментот има и `object_id` и `parent_fragment_id`. 8. **Заклучок:** `trg_fragment_check` е важен тригер за зачувување на правилната хиерархија на фрагментите. Тој спречува нелогични релации во археолошката документација и обезбедува секој фрагмент да има јасна и единствена припадност. === Тригер 2: Проверка на одобрен истражувачки пристап (trg_access_check) === 1. **Намена:** Тригерот `trg_access_check` е наменет за валидација на записите во табелата `Researcher_Access`. Неговата цел е да спречи внесување на одобрен истражувачки пристап доколку не е наведен конкретен археолошки предмет. 2. **Случај на употреба:** Во системот, истражувачите можат да побараат пристап до конкретни предмети за научна обработка, анализа или конзерваторска документација. Пристапот не смее да биде апстрактен или општ, туку мора да се однесува на точно определен артефакт. Одобрување пристап без конкретен предмет би било логички невалидно, бидејќи системот не би знаел до кој објект истражувачот добил дозвола. 3. **Причина за избор на тригер:** Тригерот е избран затоа што ова правило е поврзано со бизнис логиката на процесот на одобрување пристап. Иако `object_id` во табелата `Researcher_Access` е дефиниран како `NOT NULL`, тригерот додава дополнителна проверка за конкретен случај: кога статусот на пристап е одобрен. На тој начин правилото е експлицитно документирано во базата и директно се поврзува со статусот `access_status_id = 6`, кој во податоците се користи за статусот „Одобрено“. 4. **Имплементација:** Тригер функцијата е: {{{ CREATE OR REPLACE FUNCTION trg_block_access() RETURNS TRIGGER AS $$ BEGIN IF NEW.access_status_id = 6 AND NEW.object_id IS NULL THEN RAISE EXCEPTION 'Не може одобрен пристап без објект'; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; }}} Тригерот се активира: {{{ CREATE TRIGGER trg_access_check BEFORE INSERT ON Researcher_Access FOR EACH ROW EXECUTE FUNCTION trg_block_access(); }}} 5. **Логика на работа:** Тригерот се извршува пред внесување нов запис во `Researcher_Access`. Проверува дали: * `access_status_id = 6`, односно пристапот е одобрен * `object_id IS NULL`, односно не е наведен предмет Доколку двата услови се исполнети, внесот се блокира. 6. **Бизнис логика:** Овој тригер ја имплементира контролата на истражувачки пристап. Во контекст на културно наследство, предметите можат да имаат чувствителни информации, како точна локација на пронаоѓање, состојба, вредност, конзерваторски третмани или научна важност. Затоа секој одобрен пристап мора да биде поврзан со конкретен предмет. Ова спречува нејасни дозволи и овозможува прецизна ревизија на тоа кој корисник добил пристап до кој артефакт. 7. **Заклучок:** `trg_access_check` обезбедува дополнителна безбедност и логичка исправност во процесот на одобрување истражувачки пристап. Тој спречува креирање на невалидни записи и помага системот да одржи точна евиденција за дозволите на истражувачите. === Тригер 3: Спречување публикација без главен автор (trg_publication_check) === 1. **Намена:** Тригерот `trg_publication_check` е наменет за проверка на научните публикации пред нивно внесување или ажурирање. Неговата цел е да спречи публикација да постои без дефиниран главен автор. 2. **Случај на употреба:** Во системот се чуваат научни публикации поврзани со археолошки предмети. Публикацијата може да има повеќе автори преку табелата `Publication_Authors`, но мора да постои еден главен автор во табелата `Publications` преку полето `main_author_id`. Главниот автор е важен затоа што претставува примарно лице одговорно за публикацијата, нејзината содржина и академската евиденција. 3. **Причина за избор на тригер:** Тригерот е избран затоа што се работи за бизнис правило кое мора да важи и при внесување и при ажурирање на публикации. Иако ова правило може делумно да се реализира со `NOT NULL` constraint, тригерот овозможува експлицитна контрола и јасна порака за грешка. Дополнително, тригерот е корисен бидејќи во моделот `main_author_id` може да биде `NULL` на ниво на дефиниција на табела, но бизнис логиката бара да не се дозволува реално внесување публикација без главен автор. 4. **Имплементација:** Тригер функцијата е: {{{ CREATE OR REPLACE FUNCTION trg_pub_author_check() RETURNS TRIGGER AS $$ BEGIN IF NEW.main_author_id IS NULL THEN RAISE EXCEPTION 'Публикацијата мора да има главен автор'; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; }}} Тригерот се активира: {{{ CREATE TRIGGER trg_publication_check BEFORE INSERT OR UPDATE ON Publications FOR EACH ROW EXECUTE FUNCTION trg_pub_author_check(); }}} 5. **Логика на работа:** Тригерот се извршува пред секој `INSERT` или `UPDATE` врз табелата `Publications`. Доколку новата вредност за `main_author_id` е `NULL`, внесот или ажурирањето се прекинува и се фрла исклучок. 6. **Бизнис логика:** Овој тригер ја имплементира академската логика на системот. Во археолошки и научен контекст, секоја публикација мора да има одговорен автор. Без ова правило, системот би можел да содржи публикации без јасна одговорност, што би довело до проблеми при цитирање, библиографска обработка и научна документација. 7. **Заклучок:** `trg_publication_check` обезбедува секоја научна публикација да има главен автор. Со тоа се зачувува академскиот интегритет на податоците и се спречува внесување нецелосни публикации. === Тригер 4: Автоматско поставување статус на фрагмент (trg_fragment_auto_status) === 1. **Намена:** Тригерот `trg_fragment_auto_status` е наменет за автоматско поставување статус на нов фрагмент при негово внесување во табелата `Fragments`. 2. **Случај на употреба:** Кога се внесува нов фрагмент кој е поврзан со конкретен археолошки предмет преку `object_id`, системот автоматски му поставува иницијален статус. Ова е корисно затоа што при теренска работа или масовно внесување податоци може да се внесат голем број фрагменти, па рачното поставување статус за секој од нив би било подложно на грешки. 3. **Причина за избор на тригер:** Тригерот е избран затоа што статусот треба автоматски да се постави во моментот на внесување, врз основа на вредноста на `object_id`. Ова правило е динамично: ако фрагментот е поврзан со предмет, тогаш добива статус. Затоа е соодветно да се користи `BEFORE INSERT` тригер, кој може да ја промени вредноста на `NEW.status_id` пред записот да биде зачуван. 4. **Имплементација:** Тригер функцијата е: {{{ CREATE OR REPLACE FUNCTION trg_auto_fragment_status() RETURNS TRIGGER AS $$ BEGIN IF NEW.object_id IS NOT NULL THEN NEW.status_id := 1; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; }}} Тригерот се активира: {{{ CREATE TRIGGER trg_fragment_auto_status BEFORE INSERT ON Fragments FOR EACH ROW EXECUTE FUNCTION trg_auto_fragment_status(); }}} 5. **Логика на работа:** Тригерот се активира пред секој внес во `Fragments`. Ако новиот фрагмент има вредност во `object_id`, тогаш автоматски се поставува: {{{ NEW.status_id := 1; }}} Со тоа фрагментот добива иницијален статус без корисникот да мора рачно да го внесе. 6. **Бизнис логика:** Овој тригер ја имплементира автоматизацијата на теренската и лабораториската евиденција на фрагменти. Во систем за културно наследство, фрагментите често се внесуваат во голем број, особено при археолошки ископувања или лабораториска обработка. Автоматското поставување статус обезбедува секој фрагмент кој е поврзан со предмет да има валиден почетен статус, што го олеснува понатамошното следење, класификација и конзервација. 7. **Заклучок:** `trg_fragment_auto_status` ја намалува можноста за човечка грешка при внесување фрагменти и обезбедува поголема конзистентност во базата. Тој е особено корисен при масовно внесување археолошки материјал. === Тригер 5: Проверка на совпаѓање помеѓу проект и предмет кај истражувачки пристап (trg_researcher_access_project_match) === 1. **Намена:** Тригерот `trg_researcher_access_project_match` е наменет за проверка дали конзерваторскиот проект наведен во `Researcher_Access` навистина се однесува на истиот предмет за кој се бара истражувачки пристап. 2. **Случај на употреба:** Во системот, истражувачкиот пристап може да биде поврзан со конкретен конзерваторски проект преку `conservation_project_id`. Секој конзерваторски проект во табелата `Conservation_Projects` е поврзан со точно одреден предмет преку `object_id`. Проблемот се јавува ако истражувач побара пристап до еден предмет, но во барањето наведе конзерваторски проект кој реално припаѓа на друг предмет. Таков запис би бил логички неконзистентен и би можел да доведе до погрешно одобрување на пристап. 3. **Причина за избор на тригер:** Овој тригер е избран затоа што правилото бара споредба на вредности од две различни табели: * `Researcher_Access.object_id` * `Conservation_Projects.object_id` Обичен `FOREIGN KEY` може да провери дали `conservation_project_id` постои во `Conservation_Projects`, но не може сам да провери дали тој проект се однесува на истиот `object_id` кој е наведен во барањето за пристап. Затоа се користи тригер, бидејќи тој може да изврши дополнителен `SELECT`, да ја прочита вредноста `object_id` од проектот и да ја спореди со новиот запис во `Researcher_Access`. 4. **Имплементација:** Тригер функцијата е: {{{ CREATE OR REPLACE FUNCTION trg_validate_project_object_match() RETURNS TRIGGER AS $$ DECLARE v_project_object_id BIGINT; BEGIN IF NEW.conservation_project_id IS NULL THEN RETURN NEW; END IF; SELECT object_id INTO v_project_object_id FROM Conservation_Projects WHERE project_id = NEW.conservation_project_id; IF v_project_object_id <> NEW.object_id THEN RAISE EXCEPTION 'Конзерваторскиот проект % не припаѓа на објектот %. Пристапот е одбиен.', NEW.conservation_project_id, NEW.object_id; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; }}} Тригерот се активира: {{{ CREATE TRIGGER trg_researcher_access_project_match BEFORE INSERT OR UPDATE ON Researcher_Access FOR EACH ROW EXECUTE FUNCTION trg_validate_project_object_match(); }}} 5. **Логика на работа:** Тригерот се активира пред секој `INSERT` или `UPDATE` во `Researcher_Access`. Прво проверува дали `NEW.conservation_project_id` е `NULL`. Ако нема поврзан проект, нема што да се проверува и записот продолжува. Ако постои поврзан проект, тригерот го пронаоѓа `object_id` од табелата `Conservation_Projects` за тој проект: {{{ SELECT object_id INTO v_project_object_id FROM Conservation_Projects WHERE project_id = NEW.conservation_project_id; }}} Потоа го споредува тој `object_id` со `NEW.object_id`. Ако вредностите не се исти, записот се одбива. 6. **Бизнис логика:** Овој тригер имплементира едно од најважните правила за контрола на истражувачки пристап. Во системот, пристапот не смее да се одобри преку проект кој не се однесува на истиот предмет. На пример, ако конзерваторски проект е креиран за предмет А, истражувачот не смее да го користи тој проект како основа за пристап до предмет Б. Тоа би создало сериозна неконзистентност во системот и би можело да доведе до неовластен пристап до погрешен артефакт. Ова е особено важно кај културното наследство, бидејќи предметите можат да имаат различен степен на заштита, различни истражувачки ограничувања и различна институционална сопственост. 7. **Зошто не е доволен FOREIGN KEY:** Стандардниот `FOREIGN KEY` constraint може да провери само дали вредноста `conservation_project_id` постои како `project_id` во `Conservation_Projects`. Но правилото овде е посложено. Треба да се провери дали: {{{ Researcher_Access.conservation_project_id -> Conservation_Projects.project_id }}} и истовремено дали: {{{ Researcher_Access.object_id = Conservation_Projects.object_id }}} Ова е меѓутабеларна логичка проверка и затоа е соодветно имплементирана со тригер. 8. **Заклучок:** `trg_researcher_access_project_match` обезбедува логичка конзистентност помеѓу истражувачките барања, предметите и конзерваторските проекти. Овој тригер спречува сериозни грешки во пристапот и ја зајакнува безбедноста и точноста на системот.