--
-- PostgreSQL database dump
--

\restrict fMX8pe7fyPeennYB6eeK17lVC7rkBp0LxzYWCFMQgMflMYdB3BYjGmqxfiz2Aj2

-- Dumped from database version 18.0
-- Dumped by pg_dump version 18.4

-- Started on 2026-06-30 18:28:52 MSK

SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET transaction_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;

--
-- TOC entry 16 (class 2615 OID 442818)
-- Name: dyachkov_ya; Type: SCHEMA; Schema: -; Owner: dyachkov_ya
--

CREATE SCHEMA dyachkov_ya;


ALTER SCHEMA dyachkov_ya OWNER TO dyachkov_ya;

--
-- TOC entry 1403 (class 1255 OID 443423)
-- Name: add_user_with_phones(character varying, character varying, integer, integer, integer, character varying, real, integer, character varying, character varying); Type: PROCEDURE; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE PROCEDURE dyachkov_ya.add_user_with_phones(IN p_lastname character varying, IN p_name character varying, IN p_year_b integer, IN p_groups integer, IN p_age integer, IN p_category character varying DEFAULT NULL::character varying, IN p_debt real DEFAULT 0, IN p_level integer DEFAULT 1, IN p_home_phone character varying DEFAULT NULL::character varying, IN p_mobile_phone character varying DEFAULT NULL::character varying)
    LANGUAGE plpgsql
    AS $$
DECLARE
    v_has_phone BOOLEAN;
BEGIN
    BEGIN
        -- Проверка наличия хотя бы одного телефона
        v_has_phone := (p_home_phone IS NOT NULL AND p_home_phone != '') OR
                       (p_mobile_phone IS NOT NULL AND p_mobile_phone != '');
        
        IF NOT v_has_phone THEN
            RAISE EXCEPTION 'Необходимо указать хотя бы один телефон (домашний или мобильный) для связи с читателем';
        END IF;
        
        -- Вставка пользователя
        INSERT INTO users (lastname, name, year_b, groups, age, category, debt, level, home_phone, mobile_phone)
        VALUES (p_lastname, p_name, p_year_b, p_groups, p_age, p_category, p_debt, p_level, p_home_phone, p_mobile_phone);
        
        COMMIT;
        RAISE NOTICE 'Пользователь "% %" успешно добавлен', p_lastname, p_name;
        RAISE NOTICE 'Телефоны: дом.%, моб.%', 
                     COALESCE(p_home_phone, 'не указан'), 
                     COALESCE(p_mobile_phone, 'не указан');
        
    EXCEPTION
        WHEN OTHERS THEN
            ROLLBACK;
            RAISE NOTICE 'ОШИБКА: %', SQLERRM;
    END;
END;
$$;


ALTER PROCEDURE dyachkov_ya.add_user_with_phones(IN p_lastname character varying, IN p_name character varying, IN p_year_b integer, IN p_groups integer, IN p_age integer, IN p_category character varying, IN p_debt real, IN p_level integer, IN p_home_phone character varying, IN p_mobile_phone character varying) OWNER TO dyachkov_ya;

--
-- TOC entry 1404 (class 1255 OID 443424)
-- Name: authenticate_user(character varying, text); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.authenticate_user(p_username character varying, p_password text) RETURNS TABLE(user_id integer, username character varying, decrypted_name text, role_name character varying, is_authenticated boolean)
    LANGUAGE plpgsql
    AS $$
DECLARE
    v_user_record RECORD;
    v_decrypted_name TEXT;
BEGIN
    -- Поиск пользователя
    SELECT u.id, u.username, u.encrypted_name, u.password_hash, r.role_name
    INTO v_user_record
    FROM system_users u
    JOIN roles r ON u.role_id = r.id
    WHERE u.username = p_username AND u.is_active = TRUE;
    
    IF v_user_record.id IS NULL THEN
        RETURN QUERY SELECT NULL::INTEGER, NULL::VARCHAR, NULL::TEXT, NULL::VARCHAR, FALSE::BOOLEAN;
        RETURN;
    END IF;
    
    -- Проверка пароля
    IF v_user_record.password_hash = crypt(p_password, v_user_record.password_hash) THEN
        -- Расшифровываем имя
        BEGIN
            v_decrypted_name := convert_from(decrypt(decode(v_user_record.encrypted_name, 'base64'), 'master_key', 'aes'), 'UTF8');
        EXCEPTION WHEN OTHERS THEN
            v_decrypted_name := '[Ошибка расшифровки]';
        END;
        
        RETURN QUERY SELECT 
            v_user_record.id, 
            v_user_record.username, 
            v_decrypted_name, 
            v_user_record.role_name, 
            TRUE::BOOLEAN;
    ELSE
        RETURN QUERY SELECT NULL::INTEGER, NULL::VARCHAR, NULL::TEXT, NULL::VARCHAR, FALSE::BOOLEAN;
    END IF;
END;
$$;


ALTER FUNCTION dyachkov_ya.authenticate_user(p_username character varying, p_password text) OWNER TO dyachkov_ya;

--
-- TOC entry 1405 (class 1255 OID 443425)
-- Name: autonomous_log(integer, real, real); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.autonomous_log(p_book_bshifr integer, p_old_price real, p_new_price real) RETURNS void
    LANGUAGE plpgsql
    AS $$
BEGIN
    -- Имитация автономной транзакции
    BEGIN
        INSERT INTO logs (bk, cena_old, cena_new)
        VALUES (p_book_bshifr, p_old_price, p_new_price);
        
        -- Фиксируем лог независимо от основной транзакции
        COMMIT;
        RAISE NOTICE 'Лог сохранен автономно: книга bshifr=%, цена %.2f -> %.2f', 
                     p_book_bshifr, p_old_price, p_new_price;
    EXCEPTION
        WHEN OTHERS THEN
            RAISE NOTICE 'Не удалось сохранить лог: %', SQLERRM;
    END;
END;
$$;


ALTER FUNCTION dyachkov_ya.autonomous_log(p_book_bshifr integer, p_old_price real, p_new_price real) OWNER TO dyachkov_ya;

--
-- TOC entry 1406 (class 1255 OID 443426)
-- Name: check_ticket_constraints(); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.check_ticket_constraints() RETURNS trigger
    LANGUAGE plpgsql
    AS $$
DECLARE
user_exists BOOLEAN;
book_exists BOOLEAN;
BEGIN
SELECT EXISTS (SELECT 1 FROM users WHERE id = NEW.user_id)
INTO user_exists;
IF NOT user_exists THEN
RAISE EXCEPTION 'Ошибка: Пользователь с ID % не существует в таблице users. Запись в ticket не может быть добавлена.', NEW.user_id;
END IF;
SELECT EXISTS (SELECT 1 FROM book WHERE bshifr = NEW.book_id)
INTO book_exists;
IF NOT book_exists THEN
RAISE EXCEPTION 'Ошибка: Книга с шифром % не существует в таблице book. Запись в ticket не может быть добавлена.', NEW.book_id;
END IF;
IF NEW.date_return IS NOT NULL AND NEW.date_of_issue IS NOT NULL THEN
IF NEW.date_return < NEW.date_of_issue THEN
RAISE EXCEPTION 'Ошибка: Дата возврата (%) не может быть раньше даты выдачи (%).', NEW.date_return, NEW.date_of_issue;
END IF;
END IF;
RETURN NEW;
END;
$$;


ALTER FUNCTION dyachkov_ya.check_ticket_constraints() OWNER TO dyachkov_ya;

--
-- TOC entry 1407 (class 1255 OID 443427)
-- Name: check_user_access(character varying, character varying); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.check_user_access(p_username character varying, p_required_role character varying) RETURNS boolean
    LANGUAGE plpgsql
    AS $$
DECLARE
    v_user_role VARCHAR(50);
    v_has_access BOOLEAN := FALSE;
BEGIN
    -- Начинаем транзакцию
    BEGIN
        SELECT r.role_name INTO v_user_role
        FROM system_users u
        JOIN roles r ON u.role_id = r.id
        WHERE u.username = p_username AND u.is_active = TRUE;
        
        -- Проверка роли (admin имеет полный доступ)
        IF v_user_role = 'admin' OR v_user_role = p_required_role THEN
            v_has_access := TRUE;
        END IF;
        
        -- Логируем попытку доступа (в реальной системе)
        INSERT INTO access_log (username, access_time, has_access, required_role)
        VALUES (p_username, CURRENT_TIMESTAMP, v_has_access, p_required_role);
        
        COMMIT;
    EXCEPTION WHEN OTHERS THEN
        ROLLBACK;
        RAISE NOTICE 'Ошибка при проверке доступа: %', SQLERRM;
        v_has_access := FALSE;
    END;
    
    RETURN v_has_access;
END;
$$;


ALTER FUNCTION dyachkov_ya.check_user_access(p_username character varying, p_required_role character varying) OWNER TO dyachkov_ya;

--
-- TOC entry 1408 (class 1255 OID 443428)
-- Name: check_user_by_email(text); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.check_user_by_email(p_email text) RETURNS integer
    LANGUAGE plpgsql
    AS $$
DECLARE
    user_exists INTEGER;
    decrypted_email TEXT;
    user_record RECORD;
BEGIN
    user_exists := 0;
    
    -- Проходим по всем пользователям и расшифровываем email для сравнения
    FOR user_record IN SELECT id, email FROM users LOOP
        IF user_record.email IS NOT NULL THEN
            BEGIN
                decrypted_email := decrypt_email(user_record.email);
                IF decrypted_email = p_email THEN
                    user_exists := 1;
                    EXIT;
                END IF;
            EXCEPTION WHEN OTHERS THEN
                -- Пропускаем ошибки дешифрования
                CONTINUE;
            END;
        END IF;
    END LOOP;
    
    RETURN user_exists;
END;
$$;


ALTER FUNCTION dyachkov_ya.check_user_by_email(p_email text) OWNER TO dyachkov_ya;

--
-- TOC entry 1409 (class 1255 OID 443429)
-- Name: clean_string(text); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.clean_string(input text) RETURNS text
    LANGUAGE plpgsql
    AS $$
BEGIN
    IF input IS NULL THEN
        RETURN NULL;
    END IF;
    -- Удаление лишних пробелов, замена нескольких пробелов на один
    RETURN TRIM(REGEXP_REPLACE(input, '\s+', ' ', 'g'));
END;
$$;


ALTER FUNCTION dyachkov_ya.clean_string(input text) OWNER TO dyachkov_ya;

--
-- TOC entry 1410 (class 1255 OID 443430)
-- Name: count_books_by_user(character varying, character varying); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.count_books_by_user(p_lastname character varying, p_name character varying) RETURNS integer
    LANGUAGE plpgsql
    AS $$
DECLARE
books_count INTEGER := 0;
BEGIN
IF p_lastname IS NULL OR p_name IS NULL THEN
RAISE EXCEPTION 'Фамилия и имя пользователя не могут быть NULL.';
END IF;
SELECT COUNT(t.id)
INTO books_count
FROM ticket t
JOIN users u ON t.user_id = u.id
WHERE u.lastname = p_lastname AND u.name = p_name;
RETURN books_count;
END;
$$;


ALTER FUNCTION dyachkov_ya.count_books_by_user(p_lastname character varying, p_name character varying) OWNER TO dyachkov_ya;

--
-- TOC entry 1411 (class 1255 OID 443431)
-- Name: count_unique_readers_in_month(integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.count_unique_readers_in_month(p_month integer) RETURNS bigint
    LANGUAGE plpgsql
    AS $$
DECLARE
readers_count BIGINT := 0;
BEGIN
IF p_month IS NULL OR p_month < 1 OR p_month > 12 THEN
RAISE EXCEPTION 'Номер месяца должен быть от 1 до 12.';
END IF;
SELECT COUNT(DISTINCT t.user_id)
INTO readers_count
FROM ticket t
WHERE EXTRACT(MONTH FROM t.date_of_issue) = p_month; -- EXTRACT(MONTH FROM ...) извлекает номер месяца из даты
RETURN readers_count;
END;
$$;


ALTER FUNCTION dyachkov_ya.count_unique_readers_in_month(p_month integer) OWNER TO dyachkov_ya;

--
-- TOC entry 1412 (class 1255 OID 443432)
-- Name: days_since_issue(integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.days_since_issue(p_ticket_id integer) RETURNS integer
    LANGUAGE plpgsql
    AS $$
DECLARE
issue_date DATE;
days_elapsed INTEGER;
BEGIN
SELECT date_of_issue
INTO issue_date
FROM ticket
WHERE id = p_ticket_id;
IF NOT FOUND THEN
RAISE EXCEPTION 'Билет с ID % не найден.', p_ticket_id;
END IF;
days_elapsed := Kol_Dney(issue_date, CURRENT_DATE::date);
RETURN days_elapsed;
END;
$$;


ALTER FUNCTION dyachkov_ya.days_since_issue(p_ticket_id integer) OWNER TO dyachkov_ya;

--
-- TOC entry 1413 (class 1255 OID 443433)
-- Name: decrypt_data(text, text); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.decrypt_data(p_encrypted text, p_key text DEFAULT 'default_key'::text) RETURNS text
    LANGUAGE plpgsql
    AS $$
DECLARE
    result TEXT;
BEGIN
    result := convert_from(decrypt(decode(p_encrypted, 'hex'), p_key, 'aes'), 'UTF8');
    RETURN result;
EXCEPTION WHEN OTHERS THEN
    RETURN 'Ошибка дешифрования';
END;
$$;


ALTER FUNCTION dyachkov_ya.decrypt_data(p_encrypted text, p_key text) OWNER TO dyachkov_ya;

--
-- TOC entry 1414 (class 1255 OID 443435)
-- Name: decrypt_email(text); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.decrypt_email(encrypted_email text) RETURNS text
    LANGUAGE plpgsql
    AS $$
DECLARE
    decrypted_email TEXT;
BEGIN
    IF encrypted_email IS NULL THEN
        RETURN NULL;
    END IF;
    
    BEGIN
        decrypted_email := convert_from(decrypt(decode(encrypted_email, 'base64'), 'my_secret_key', 'aes'), 'UTF8');
        RETURN decrypted_email;
    EXCEPTION WHEN OTHERS THEN
        RETURN encrypted_email; -- Если не зашифровано, возвращаем как есть
    END;
END;
$$;


ALTER FUNCTION dyachkov_ya.decrypt_email(encrypted_email text) OWNER TO dyachkov_ya;

--
-- TOC entry 1415 (class 1255 OID 443436)
-- Name: delete_book(integer); Type: PROCEDURE; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE PROCEDURE dyachkov_ya.delete_book(IN p_bshifr integer)
    LANGUAGE plpgsql
    AS $$
DECLARE
    v_title VARCHAR(25);
    v_vidano BOOLEAN;
BEGIN
    BEGIN
        -- Получаем информацию о книге
        SELECT title, vidano INTO v_title, v_vidano
        FROM book WHERE bshifr = p_bshifr;
        
        IF NOT FOUND THEN
            RAISE EXCEPTION 'Книга с bshifr=% не найдена', p_bshifr;
        END IF;
        
        -- Проверка: если книга на руках - запрещаем удаление
        IF v_vidano = TRUE THEN
            RAISE EXCEPTION 'Невозможно удалить книгу "%" - экземпляр находится на руках у читателя', v_title;
        END IF;
        
        -- Удаляем книгу
        DELETE FROM book WHERE bshifr = p_bshifr;
        
        COMMIT;
        RAISE NOTICE 'Книга "% (bshifr=%) успешно удалена', v_title, p_bshifr;
        
    EXCEPTION
        WHEN OTHERS THEN
            ROLLBACK;
            RAISE NOTICE 'ОШИБКА: %', SQLERRM;
    END;
END;
$$;


ALTER PROCEDURE dyachkov_ya.delete_book(IN p_bshifr integer) OWNER TO dyachkov_ya;

--
-- TOC entry 1416 (class 1255 OID 443437)
-- Name: delete_reader(integer); Type: PROCEDURE; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE PROCEDURE dyachkov_ya.delete_reader(IN p_user_id integer)
    LANGUAGE plpgsql
    AS $$
DECLARE
    v_books_count INTEGER;
    v_username VARCHAR(50);
    v_books_list TEXT;
BEGIN
    BEGIN
        -- Получаем имя пользователя
        SELECT lastname || ' ' || name INTO v_username
        FROM users WHERE id = p_user_id;
        
        IF NOT FOUND THEN
            RAISE EXCEPTION 'Пользователь с ID % не найден', p_user_id;
        END IF;
        
        -- Подсчет книг на руках
        SELECT COUNT(*) INTO v_books_count
        FROM ticket
        WHERE user_id = p_user_id 
          AND (date_of_return IS NULL OR date_of_return > CURRENT_DATE);
        
        -- Если есть книги - формируем список и выдаем ошибку
        IF v_books_count > 0 THEN
            SELECT STRING_AGG(b.title, ', ') INTO v_books_list
            FROM ticket t
            JOIN book b ON t.book_id = b.bshifr
            WHERE t.user_id = p_user_id 
              AND (t.date_of_return IS NULL OR t.date_of_return > CURRENT_DATE);
            
            RAISE EXCEPTION 'Невозможно удалить читателя "%". У него на руках % книг: %',
                            v_username, v_books_count, v_books_list;
        END IF;
        
        -- Удаляем пользователя
        DELETE FROM users WHERE id = p_user_id;
        
        COMMIT;
        RAISE NOTICE 'Читатель "% (ID: %) успешно удален', v_username, p_user_id;
        
    EXCEPTION
        WHEN OTHERS THEN
            ROLLBACK;
            RAISE NOTICE 'ОШИБКА: %', SQLERRM;
    END;
END;
$$;


ALTER PROCEDURE dyachkov_ya.delete_reader(IN p_user_id integer) OWNER TO dyachkov_ya;

--
-- TOC entry 1417 (class 1255 OID 443438)
-- Name: encrypt_data(text, text); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.encrypt_data(p_data text, p_key text DEFAULT 'default_key'::text) RETURNS text
    LANGUAGE plpgsql
    AS $$
BEGIN
    RETURN encode(encrypt(p_data::bytea, p_key, 'aes'), 'hex');
END;
$$;


ALTER FUNCTION dyachkov_ya.encrypt_data(p_data text, p_key text) OWNER TO dyachkov_ya;

--
-- TOC entry 1418 (class 1255 OID 443439)
-- Name: encrypt_email(); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.encrypt_email() RETURNS trigger
    LANGUAGE plpgsql
    AS $$
BEGIN
    IF NEW.email IS NOT NULL AND NEW.email != '' THEN
        -- Используем симметричное шифрование с ключом 'secret_key'
        NEW.email := encode(encrypt(NEW.email::bytea, 'my_secret_key', 'aes'), 'base64');
    END IF;
    RETURN NEW;
END;
$$;


ALTER FUNCTION dyachkov_ya.encrypt_email() OWNER TO dyachkov_ya;

--
-- TOC entry 1419 (class 1255 OID 443440)
-- Name: generate_random_id_for_usernew(); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.generate_random_id_for_usernew() RETURNS trigger
    LANGUAGE plpgsql
    AS $$
DECLARE
    new_id INTEGER;
    is_unique BOOLEAN := FALSE;
    max_attempts INTEGER := 100; -- Количество попыток генерации ID
    current_attempt INTEGER := 0;
BEGIN
    -- Если ID уже предоставлен (НЕ NULL), оставляем его.
    IF NEW.id IS NOT NULL THEN
        RETURN NEW;
    END IF;

    -- Генерируем новый ID, пока он не станет уникальным.
    WHILE NOT is_unique LOOP
        -- Генерируем случайное число (диапазон 1 - 1000000).
        new_id := floor(random() * 1000000 + 1);

        -- Проверяем уникальность ID.
        IF NOT EXISTS (SELECT 1 FROM usernew WHERE id = new_id) THEN
            is_unique := TRUE;
        END IF;
        
        current_attempt := current_attempt + 1;
        -- Защита от бесконечного цикла.
        IF current_attempt > max_attempts THEN
            RAISE EXCEPTION 'Не удалось сгенерировать уникальный ID для usernew после % попыток.', max_attempts;
        END IF;
    END LOOP;
    
    -- Присваиваем сгенерированный ID.
    NEW.id := new_id;
    
    RETURN NEW;
END;
$$;


ALTER FUNCTION dyachkov_ya.generate_random_id_for_usernew() OWNER TO dyachkov_ya;

--
-- TOC entry 1420 (class 1255 OID 443441)
-- Name: generate_sentence_from_dict(integer, text); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.generate_sentence_from_dict(p_word_count integer, p_separator text DEFAULT ' '::text) RETURNS text
    LANGUAGE plpgsql
    AS $$
DECLARE
    v_words TEXT[];
    v_sentence TEXT := '';
    v_capitalized_word TEXT;
    i INTEGER;
BEGIN
    -- Получаем случайные слова
    v_words := get_random_words(p_word_count);
    
    -- Формируем предложение
    FOR i IN 1..array_length(v_words, 1) LOOP
        IF i = 1 THEN
            -- Первое слово с заглавной буквы
            v_sentence := v_sentence || initcap(v_words[i]);
        ELSE
            v_sentence := v_sentence || p_separator || lower(v_words[i]);
        END IF;
    END LOOP;
    
    -- Добавляем точку в конце
    v_sentence := v_sentence || '.';
    
    RETURN v_sentence;
END;
$$;


ALTER FUNCTION dyachkov_ya.generate_sentence_from_dict(p_word_count integer, p_separator text) OWNER TO dyachkov_ya;

--
-- TOC entry 1421 (class 1255 OID 443442)
-- Name: generate_uuid_and_time(); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.generate_uuid_and_time() RETURNS trigger
    LANGUAGE plpgsql
    AS $$
BEGIN
    IF NEW.uuid IS NULL THEN
        NEW.uuid := gen_random_uuid();
    END IF;
    NEW.time_created := CURRENT_TIMESTAMP;
    RETURN NEW;
END;
$$;


ALTER FUNCTION dyachkov_ya.generate_uuid_and_time() OWNER TO dyachkov_ya;

--
-- TOC entry 1849 (class 1255 OID 444742)
-- Name: get_exhibit_count_by_author(integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.get_exhibit_count_by_author(author_id integer) RETURNS integer
    LANGUAGE plpgsql
    AS $$
DECLARE
    exhibit_count INTEGER;
BEGIN
    SELECT COUNT(*) INTO exhibit_count
    FROM Exhibit
    WHERE id_creator = author_id;
    
    RETURN exhibit_count;
END;
$$;


ALTER FUNCTION dyachkov_ya.get_exhibit_count_by_author(author_id integer) OWNER TO dyachkov_ya;

--
-- TOC entry 1422 (class 1255 OID 443443)
-- Name: get_most_expensive_book_by_author(character varying); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.get_most_expensive_book_by_author(p_author_lastname character varying) RETURNS character varying
    LANGUAGE plpgsql
    AS $$
DECLARE
book_title_result VARCHAR(255);
BEGIN
IF p_author_lastname IS NULL THEN
RAISE EXCEPTION 'Фамилия автора не может быть NULL.';
END IF;
SELECT b.title
INTO book_title_result
FROM book b
JOIN author a ON b.id_author = a.id
WHERE a.lastname = p_author_lastname 
ORDER BY b.price DESC 
LIMIT 1; 
IF NOT FOUND THEN
RAISE NOTICE 'Автор "%" не найден или у него нет книг в базе.', p_author_lastname;
RETURN NULL; -- Возвращаем NULL, если ничего не найдено.
END IF;
RETURN book_title_result;
END;
$$;


ALTER FUNCTION dyachkov_ya.get_most_expensive_book_by_author(p_author_lastname character varying) OWNER TO dyachkov_ya;

--
-- TOC entry 1423 (class 1255 OID 443444)
-- Name: get_random_sentence(integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.get_random_sentence(word_count integer DEFAULT 5) RETURNS text
    LANGUAGE plpgsql
    AS $$
DECLARE
    words TEXT[];
    sentence TEXT := '';
    i INTEGER;
BEGIN
    words := get_random_words(word_count);
    
    FOR i IN 1..array_length(words, 1) LOOP
        IF i > 1 THEN
            sentence := sentence || ' ';
        END IF;
        sentence := sentence || words[i];
    END LOOP;
    
    RETURN sentence || '.';
END;
$$;


ALTER FUNCTION dyachkov_ya.get_random_sentence(word_count integer) OWNER TO dyachkov_ya;

--
-- TOC entry 1424 (class 1255 OID 443445)
-- Name: get_random_words(integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.get_random_words(word_count integer DEFAULT 1) RETURNS text[]
    LANGUAGE plpgsql
    AS $$
DECLARE
    words_array TEXT[];
    result_array TEXT[] := '{}';
    i INTEGER;
    random_index INTEGER;
BEGIN
    -- Пытаемся прочитать файл со словами
    BEGIN
        SELECT string_to_array(pg_read_file('/usr/share/dict/words', 0, 1000000), E'\n') INTO words_array;
    EXCEPTION WHEN OTHERS THEN
        -- Если файл не доступен, используем встроенный словарь
        words_array := ARRAY['apple', 'table', 'chair', 'house', 'computer', 'program', 'database', 'security', 'encryption', 'hash'];
    END;
    
    -- Проверяем, что массив не пустой
    IF array_length(words_array, 1) IS NULL THEN
        words_array := ARRAY['apple', 'table', 'chair', 'house', 'computer'];
    END IF;
    
    -- Выбираем случайные слова
    FOR i IN 1..word_count LOOP
        random_index := 1 + floor(random() * array_length(words_array, 1))::INTEGER;
        result_array := array_append(result_array, words_array[random_index]);
    END LOOP;
    
    RETURN result_array;
END;
$$;


ALTER FUNCTION dyachkov_ya.get_random_words(word_count integer) OWNER TO dyachkov_ya;

--
-- TOC entry 1425 (class 1255 OID 443446)
-- Name: get_ticket_details_refcursor(integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.get_ticket_details_refcursor(p_ticket_id integer) RETURNS refcursor
    LANGUAGE plpgsql
    AS $$
DECLARE
ticket_cur REFCURSOR;
BEGIN
IF p_ticket_id IS NULL THEN
RAISE EXCEPTION 'ID билета не может быть NULL.';
END IF;
OPEN ticket_cur FOR
SELECT
u.lastname AS user_lastname,
b.title AS book_title,
t.date_of_issue AS ticket_date
FROM ticket t
JOIN users u ON t.user_id = u.id
JOIN book b ON t.book_id = b.bshifr
WHERE t.id = p_ticket_id;
RETURN ticket_cur;
END;
$$;


ALTER FUNCTION dyachkov_ya.get_ticket_details_refcursor(p_ticket_id integer) OWNER TO dyachkov_ya;

--
-- TOC entry 1838 (class 1255 OID 444504)
-- Name: getaverageratingforexhibit(integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.getaverageratingforexhibit(exhibit_id integer) RETURNS numeric
    LANGUAGE plpgsql
    AS $$
DECLARE
    avg_rating DECIMAL(3,2);
BEGIN
    SELECT AVG(exhibit_rating) INTO avg_rating
    FROM Viewing
    WHERE id_exhibit = exhibit_id;
    
    RETURN COALESCE(avg_rating, 0);
END;
$$;


ALTER FUNCTION dyachkov_ya.getaverageratingforexhibit(exhibit_id integer) OWNER TO dyachkov_ya;

--
-- TOC entry 1836 (class 1255 OID 444502)
-- Name: getexhibitcountbyauthor(integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.getexhibitcountbyauthor(author_id integer) RETURNS integer
    LANGUAGE plpgsql
    AS $$
DECLARE
    exhibit_count INT;
BEGIN
    SELECT COUNT(*) INTO exhibit_count
    FROM Exhibit
    WHERE id_creator = author_id;
    
    RETURN exhibit_count;
END;
$$;


ALTER FUNCTION dyachkov_ya.getexhibitcountbyauthor(author_id integer) OWNER TO dyachkov_ya;

--
-- TOC entry 1837 (class 1255 OID 444503)
-- Name: getexhibitsbyauthor(integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.getexhibitsbyauthor(author_id integer) RETURNS TABLE(id_exhibit integer, type character varying, creation_date date, copy_price numeric, creation_cost numeric)
    LANGUAGE plpgsql
    AS $$
BEGIN
    RETURN QUERY
    SELECT e.id_exhibit, e.type, e.creation_date, e.copy_price, e.creation_cost
    FROM Exhibit e
    WHERE e.id_creator = author_id;
END;
$$;


ALTER FUNCTION dyachkov_ya.getexhibitsbyauthor(author_id integer) OWNER TO dyachkov_ya;

--
-- TOC entry 1840 (class 1255 OID 444506)
-- Name: getmuseumtotalvalue(integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.getmuseumtotalvalue(museum_id integer) RETURNS numeric
    LANGUAGE plpgsql
    AS $$
DECLARE
    total_value DECIMAL(15,2);
BEGIN
    SELECT SUM(e.copy_price) INTO total_value
    FROM Exhibit e
    WHERE e.id_museum = museum_id;
    
    RETURN COALESCE(total_value, 0);
END;
$$;


ALTER FUNCTION dyachkov_ya.getmuseumtotalvalue(museum_id integer) OWNER TO dyachkov_ya;

--
-- TOC entry 1839 (class 1255 OID 444505)
-- Name: gettop5expensiveexhibits(); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.gettop5expensiveexhibits() RETURNS TABLE(id_exhibit integer, type character varying, copy_price numeric, author_name character varying)
    LANGUAGE plpgsql
    AS $$
BEGIN
    RETURN QUERY
    SELECT e.id_exhibit, e.type, e.copy_price, c.full_name
    FROM Exhibit e
    JOIN Creator c ON e.id_creator = c.id_creator
    ORDER BY e.copy_price DESC
    LIMIT 5;
END;
$$;


ALTER FUNCTION dyachkov_ya.gettop5expensiveexhibits() OWNER TO dyachkov_ya;

--
-- TOC entry 1426 (class 1255 OID 443447)
-- Name: hash_password(text, text); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.hash_password(p_password text, p_salt text DEFAULT NULL::text) RETURNS text
    LANGUAGE plpgsql
    AS $$
DECLARE
    salt TEXT;
    hashed_password TEXT;
BEGIN
    -- Генерируем соль, если не передана
    IF p_salt IS NULL THEN
        salt := gen_salt('bf'); -- Blowfish алгоритм
    ELSE
        salt := p_salt;
    END IF;
    
    -- Создаём хэш пароля
    hashed_password := crypt(p_password, salt);
    RETURN hashed_password;
END;
$$;


ALTER FUNCTION dyachkov_ya.hash_password(p_password text, p_salt text) OWNER TO dyachkov_ya;

--
-- TOC entry 1427 (class 1255 OID 443448)
-- Name: increase_price_by_cursor(); Type: PROCEDURE; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE PROCEDURE dyachkov_ya.increase_price_by_cursor()
    LANGUAGE plpgsql
    AS $$
DECLARE
    v_book RECORD;
    v_new_price REAL;
    v_increase REAL := 20; -- 20%
    v_max_price REAL := 10000;
    v_processed INTEGER := 0;
    v_updated INTEGER := 0;
BEGIN
    -- Курсор для книг авторов, родившихся менее 1950 года
    FOR v_book IN 
        SELECT b.bshifr, b.title, b.price, a.lastname, a.name, a.year_b
        FROM book b
        JOIN author a ON b.id_author = a.id
        WHERE a.year_b < 1950
    LOOP
        -- Создаем точку сохранения для каждой книги
        PERFORM 1;
        
        BEGIN
            -- Вычисляем новую цену (+20%)
            v_new_price := v_book.price * (1 + v_increase / 100);
            
            RAISE NOTICE 'Книга: "%", Автор: % % (род. %), Цена: % -> %',
                        v_book.title, v_book.lastname, v_book.name, 
                        v_book.year_b, v_book.price, v_new_price;
            
            -- Проверка: не превышает ли новая цена 10000
            IF v_new_price <= v_max_price THEN
                UPDATE book SET price = v_new_price WHERE bshifr = v_book.bshifr;
                v_updated := v_updated + 1;
                RAISE NOTICE '  -> ЦЕНА УВЕЛИЧЕНА';
            ELSE
                -- Цена не изменяется, просто пропускаем
                RAISE NOTICE '  -> ЦЕНА НЕ ИЗМЕНЕНА (%.2f превысила бы лимит %.0f)', v_new_price, v_max_price;
            END IF;
            
            v_processed := v_processed + 1;
            
        EXCEPTION
            WHEN OTHERS THEN
                -- При ошибке просто пропускаем книгу
                RAISE NOTICE '  -> ОШИБКА при обработке книги "%": %', v_book.title, SQLERRM;
        END;
    END LOOP;
    
    RAISE NOTICE '=========================================';
    RAISE NOTICE 'Обработано книг: %, Обновлено: %', v_processed, v_updated;
    RAISE NOTICE '=========================================';
END;
$$;


ALTER PROCEDURE dyachkov_ya.increase_price_by_cursor() OWNER TO dyachkov_ya;

--
-- TOC entry 1428 (class 1255 OID 443449)
-- Name: issue_book(integer, integer, date); Type: PROCEDURE; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE PROCEDURE dyachkov_ya.issue_book(IN p_user_id integer, IN p_book_bshifr integer, IN p_date_issue date)
    LANGUAGE plpgsql
    AS $$
DECLARE
    v_books_count INTEGER;
    v_title VARCHAR(25);
    v_username VARCHAR(50);
    v_available BOOLEAN;
BEGIN
    BEGIN
        -- Получаем имя пользователя
        SELECT lastname || ' ' || name INTO v_username
        FROM users WHERE id = p_user_id;
        
        IF NOT FOUND THEN
            RAISE EXCEPTION 'Пользователь с ID % не найден', p_user_id;
        END IF;
        
        -- Получаем информацию о книге
        SELECT title, vidano INTO v_title, v_available
        FROM book WHERE bshifr = p_book_bshifr;
        
        IF NOT FOUND THEN
            RAISE EXCEPTION 'Книга с bshifr=% не найдена', p_book_bshifr;
        END IF;
        
        -- Проверка доступности книги
        IF v_available = TRUE THEN
            RAISE EXCEPTION 'Книга "%" уже выдана другому читателю', v_title;
        END IF;
        
        -- Подсчет книг на руках у читателя
        SELECT COUNT(*) INTO v_books_count
        FROM ticket
        WHERE user_id = p_user_id 
          AND (date_of_return IS NULL OR date_of_return > CURRENT_DATE);
        
        RAISE NOTICE 'У читателя "%" на руках % книг', v_username, v_books_count;
        
        -- Проверка лимита (не более 3)
        IF v_books_count >= 3 THEN
            RAISE EXCEPTION 'Читатель "%" уже имеет % книг на руках (максимум 3)', 
                            v_username, v_books_count;
        END IF;
        
        -- Выдача книги
        INSERT INTO ticket (user_id, book_id, date_of_issue, date_of_return)
        VALUES (p_user_id, p_book_bshifr, p_date_issue, NULL);
        
        UPDATE book SET vidano = TRUE WHERE bshifr = p_book_bshifr;
        
        COMMIT;
        RAISE NOTICE 'Книга "%" выдана читателю "%"', v_title, v_username;
        
    EXCEPTION
        WHEN OTHERS THEN
            ROLLBACK;
            RAISE NOTICE 'ОШИБКА: %', SQLERRM;
    END;
END;
$$;


ALTER PROCEDURE dyachkov_ya.issue_book(IN p_user_id integer, IN p_book_bshifr integer, IN p_date_issue date) OWNER TO dyachkov_ya;

--
-- TOC entry 1429 (class 1255 OID 443450)
-- Name: kol_dney(date, date); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.kol_dney(date1 date, date2 date) RETURNS integer
    LANGUAGE plpgsql
    AS $$
DECLARE
    num_days INTEGER;
BEGIN
    IF date1 IS NULL OR date2 IS NULL THEN
        RAISE EXCEPTION 'Даты не могут быть NULL.';
    END IF;

    -- В PostgreSQL разница между двумя DATE автоматически возвращает количество дней.
    num_days := date2 - date1;

    RETURN num_days; -- Возвращаем разницу в днях
END;
$$;


ALTER FUNCTION dyachkov_ya.kol_dney(date1 date, date2 date) OWNER TO dyachkov_ya;

--
-- TOC entry 1430 (class 1255 OID 443451)
-- Name: month_name_by_number(integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.month_name_by_number(month_num integer) RETURNS character varying
    LANGUAGE plpgsql
    AS $$
BEGIN
IF month_num IS NULL OR month_num < 1 OR month_num > 12 THEN
RAISE EXCEPTION 'Номер месяца должен быть от 1 до 12.';
END IF;
RETURN CASE month_num
WHEN 1 THEN 'Январь'
WHEN 2 THEN 'Февраль'
WHEN 3 THEN 'Март'
WHEN 4 THEN 'Апрель'
WHEN 5 THEN 'Май'
WHEN 6 THEN 'Июнь'
WHEN 7 THEN 'Июль'
WHEN 8 THEN 'Август'
WHEN 9 THEN 'Сентябрь'
WHEN 10 THEN 'Октябрь'
WHEN 11 THEN 'Ноябрь'
WHEN 12 THEN 'Декабрь'
ELSE 'Неизвестный месяц'
END;
END;
$$;


ALTER FUNCTION dyachkov_ya.month_name_by_number(month_num integer) OWNER TO dyachkov_ya;

--
-- TOC entry 1431 (class 1255 OID 443452)
-- Name: multi_hash(text, integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.multi_hash(p_value text, p_iterations integer DEFAULT 1) RETURNS text
    LANGUAGE plpgsql
    AS $$
DECLARE
    hashed_value TEXT;
    i INTEGER;
BEGIN
    IF p_value IS NULL THEN
        RETURN NULL;
    END IF;
    
    hashed_value := p_value;
    
    FOR i IN 1..p_iterations LOOP
        hashed_value := encode(digest(hashed_value, 'sha256'), 'hex');
    END LOOP;
    
    RETURN hashed_value;
END;
$$;


ALTER FUNCTION dyachkov_ya.multi_hash(p_value text, p_iterations integer) OWNER TO dyachkov_ya;

--
-- TOC entry 1432 (class 1255 OID 443453)
-- Name: normalize_region(text); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.normalize_region(region_name text) RETURNS text
    LANGUAGE plpgsql
    AS $$
BEGIN
    RETURN CASE
        WHEN region_name ILIKE '%Санкт-Петербург%' OR region_name ILIKE '%СПб%' THEN 'Санкт-Петербург'
        WHEN region_name ILIKE '%Ленинградская%' THEN 'Ленинградская область'
        WHEN region_name ILIKE '%Новгород%' THEN 'Новгородская область'
        ELSE clean_string(region_name)
    END;
END;
$$;


ALTER FUNCTION dyachkov_ya.normalize_region(region_name text) OWNER TO dyachkov_ya;

--
-- TOC entry 1433 (class 1255 OID 443454)
-- Name: nvl(anyelement, anyelement); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.nvl(input_value anyelement, default_value anyelement) RETURNS anyelement
    LANGUAGE plpgsql
    AS $$
BEGIN
    RETURN COALESCE(input_value, default_value);
END;
$$;


ALTER FUNCTION dyachkov_ya.nvl(input_value anyelement, default_value anyelement) OWNER TO dyachkov_ya;

--
-- TOC entry 1434 (class 1255 OID 443455)
-- Name: parse_salary(text); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.parse_salary(salary_text text) RETURNS TABLE(min_salary numeric, max_salary numeric)
    LANGUAGE plpgsql
    AS $$
DECLARE
    numbers NUMERIC[];
BEGIN
    IF salary_text IS NULL THEN
        min_salary := NULL;
        max_salary := NULL;
        RETURN NEXT;
        RETURN;
    END IF;
    
    -- Извлечение чисел из строки
    SELECT ARRAY(
        SELECT REGEXP_MATCHES(salary_text, '(\d+[.,]?\d*)', 'g')
    ) INTO numbers;
    
    IF array_length(numbers, 1) >= 1 THEN
        min_salary := numbers[1]::NUMERIC;
        IF array_length(numbers, 1) >= 2 THEN
            max_salary := numbers[2]::NUMERIC;
        ELSE
            max_salary := min_salary;
        END IF;
    ELSE
        min_salary := NULL;
        max_salary := NULL;
    END IF;
    
    RETURN NEXT;
END;
$$;


ALTER FUNCTION dyachkov_ya.parse_salary(salary_text text) OWNER TO dyachkov_ya;

--
-- TOC entry 1435 (class 1255 OID 443456)
-- Name: proizv(integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.proizv(n integer) RETURNS bigint
    LANGUAGE plpgsql
    AS $$
DECLARE
    i INTEGER;
    total_product BIGINT := 1; -- Инициализируем произведение единицей
BEGIN
    IF n IS NULL OR n <= 0 THEN
        RAISE EXCEPTION 'Параметр n должен быть положительным целым числом.';
    END IF;

    -- Цикл от 1 до n
    FOR i IN 1..n LOOP
        total_product := total_product * i; -- Умножаем текущее число на произведение
    END LOOP;

    RETURN total_product; -- Возвращаем вычисленное произведение
END;
$$;


ALTER FUNCTION dyachkov_ya.proizv(n integer) OWNER TO dyachkov_ya;

--
-- TOC entry 1436 (class 1255 OID 443457)
-- Name: proverka(integer, integer, date, date); Type: PROCEDURE; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE PROCEDURE dyachkov_ya.proverka(IN kodu integer, IN kodb integer, IN dvid date, IN dvoz date)
    LANGUAGE plpgsql
    AS $$
DECLARE
    rez VARCHAR(10) := 'ОК';
    pr INTEGER;
    v_last_id INTEGER;
BEGIN
    -- Начинаем транзакцию
    BEGIN
        -- Ввод записи в таблицу ticket (она же bilet)
        INSERT INTO ticket (user_id, book_id, date_of_issue, date_of_return)
        VALUES (kodU, kodB, dVid, dVoz)
        RETURNING id INTO v_last_id;
        
        RAISE NOTICE 'Вставлена запись с ID: %', v_last_id;
        
        -- Вычисляем разницу между датой возврата и датой выдачи
        SELECT (date_of_return - date_of_issue) INTO pr
        FROM ticket WHERE id = v_last_id;
        
        RAISE NOTICE 'Разница между датами: % дней', pr;
        
        -- Проверка: если разница > 0, то фиксируем, иначе откатываем
        IF pr > 0 THEN
            COMMIT;
            rez := 'ОК';
            RAISE NOTICE 'Дата возврата корректна. Транзакция зафиксирована.';
        ELSE
            ROLLBACK;
            rez := 'No';
            RAISE NOTICE 'ОШИБКА: дата возврата (%) меньше или равна дате выдачи (%)', dVoz, dVid;
            RAISE NOTICE 'Транзакция откачена.';
        END IF;
        
        -- Выводим значение переменной rez
        RAISE NOTICE 'Результат: %', rez;
        
    EXCEPTION
        WHEN OTHERS THEN
            ROLLBACK;
            rez := 'Error';
            RAISE NOTICE 'Ошибка при выполнении: %', SQLERRM;
    END;
END;
$$;


ALTER PROCEDURE dyachkov_ya.proverka(IN kodu integer, IN kodb integer, IN dvid date, IN dvoz date) OWNER TO dyachkov_ya;

--
-- TOC entry 1437 (class 1255 OID 443458)
-- Name: register_user(character varying, text, text, character varying); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.register_user(p_username character varying, p_name text, p_password text, p_role_name character varying DEFAULT 'user'::character varying) RETURNS integer
    LANGUAGE plpgsql
    AS $$
DECLARE
    v_salt TEXT;
    v_role_id INTEGER;
    v_encrypted_name TEXT;
    v_user_id INTEGER;
BEGIN
    -- Получаем ID роли
    SELECT id INTO v_role_id FROM roles WHERE role_name = p_role_name;
    IF v_role_id IS NULL THEN
        RAISE EXCEPTION 'Роль "%" не существует', p_role_name;
    END IF;
    
    -- Генерируем соль
    v_salt := gen_salt('bf');
    
    -- Шифруем имя пользователя (используем AES)
    v_encrypted_name := encode(encrypt(p_name::bytea, 'master_key', 'aes'), 'base64');
    
    -- Вставляем пользователя
    INSERT INTO system_users (username, encrypted_name, password_hash, salt, role_id)
    VALUES (p_username, v_encrypted_name, crypt(p_password, v_salt), v_salt, v_role_id)
    RETURNING id INTO v_user_id;
    
    RETURN v_user_id;
EXCEPTION WHEN unique_violation THEN
    RAISE EXCEPTION 'Пользователь с именем "%" уже существует', p_username;
END;
$$;


ALTER FUNCTION dyachkov_ya.register_user(p_username character varying, p_name text, p_password text, p_role_name character varying) OWNER TO dyachkov_ya;

--
-- TOC entry 1438 (class 1255 OID 443459)
-- Name: summa(integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.summa(n integer) RETURNS bigint
    LANGUAGE plpgsql
    AS $$
DECLARE
    i INTEGER;
    total_sum BIGINT := 0; -- Инициализируем сумму нулем
BEGIN
    IF n IS NULL OR n <= 0 THEN
        RAISE EXCEPTION 'Параметр n должен быть положительным целым числом.';
    END IF;

    -- Цикл от 1 до n
    FOR i IN 1..n LOOP
        total_sum := total_sum + i; -- Добавляем текущее число к сумме
    END LOOP;

    RETURN total_sum; -- Возвращаем вычисленную сумму
END;
$$;


ALTER FUNCTION dyachkov_ya.summa(n integer) OWNER TO dyachkov_ya;

--
-- TOC entry 1439 (class 1255 OID 443460)
-- Name: tek_vr(integer); Type: PROCEDURE; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE PROCEDURE dyachkov_ya.tek_vr(IN n integer)
    LANGUAGE plpgsql
    AS $$
DECLARE
    i INTEGER;
BEGIN
    IF n IS NULL OR n <= 0 THEN
        RAISE EXCEPTION 'Параметр N должен быть положительным числом.';
    END IF;

    RAISE NOTICE '--- Вывод текущего времени % раз ---', n;
    
    FOR i IN 1..n LOOP
        -- NOW() возвращает текущую дату и время
        RAISE NOTICE 'Итерация %: Текущее время: %', i, NOW();
    END LOOP;
END;
$$;


ALTER PROCEDURE dyachkov_ya.tek_vr(IN n integer) OWNER TO dyachkov_ya;

--
-- TOC entry 1440 (class 1255 OID 443461)
-- Name: ticket_insert_trigger(); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.ticket_insert_trigger() RETURNS trigger
    LANGUAGE plpgsql
    AS $$
BEGIN
IF ( NEW.date_of_issue >= DATE '2024-01-01' AND NEW.date_of_issue < DATE '2024-02-01' ) THEN INSERT INTO ticket2024m1 VALUES (NEW.*);
ELSIF ( NEW.date_of_issue >= DATE '2024-02-01' AND NEW.date_of_issue < DATE '2024-03-01' ) THEN INSERT INTO ticket2024m2 VALUES (NEW.*);
ELSIF ( NEW.date_of_issue >= DATE '2024-03-01' AND NEW.date_of_issue < DATE '2024-04-01' ) THEN INSERT INTO ticket2024m3 VALUES (NEW.*);
ELSIF ( NEW.date_of_issue >= DATE '2024-04-01' AND NEW.date_of_issue < DATE '2024-05-01' ) THEN INSERT INTO ticket2024m4 VALUES (NEW.*);
ELSIF ( NEW.date_of_issue >= DATE '2024-05-01' AND NEW.date_of_issue < DATE '2024-06-01' ) THEN INSERT INTO ticket2024m5 VALUES (NEW.*);
ELSIF ( NEW.date_of_issue >= DATE '2024-06-01' AND NEW.date_of_issue < DATE '2024-07-01' ) THEN INSERT INTO ticket2024m6 VALUES (NEW.*);
ELSIF ( NEW.date_of_issue >= DATE '2024-07-01' AND NEW.date_of_issue < DATE '2024-08-01' ) THEN INSERT INTO ticket2024m7 VALUES (NEW.*);
ELSIF ( NEW.date_of_issue >= DATE '2024-08-01' AND NEW.date_of_issue < DATE '2024-09-01' ) THEN INSERT INTO ticket2024m8 VALUES (NEW.*);
ELSIF ( NEW.date_of_issue >= DATE '2024-09-01' AND NEW.date_of_issue < DATE '2024-10-01' ) THEN INSERT INTO ticket2024m9 VALUES (NEW.*);
ELSIF ( NEW.date_of_issue >= DATE '2024-10-01' AND NEW.date_of_issue < DATE '2024-11-01' ) THEN INSERT INTO ticket2024m10 VALUES (NEW.*);
ELSIF ( NEW.date_of_issue >= DATE '2024-11-01' AND NEW.date_of_issue < DATE '2024-12-01' ) THEN INSERT INTO ticket2024m11 VALUES (NEW.*);
ELSIF ( NEW.date_of_issue >= DATE '2024-12-01' AND NEW.date_of_issue < DATE '2025-01-01' ) THEN INSERT INTO ticket2024m12 VALUES (NEW.*);
ELSE RAISE EXCEPTION 'Date out of range for all partitions';
END IF;
RETURN NULL;
END;
$$;


ALTER FUNCTION dyachkov_ya.ticket_insert_trigger() OWNER TO dyachkov_ya;

--
-- TOC entry 1441 (class 1255 OID 443462)
-- Name: track_price_change(); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.track_price_change() RETURNS trigger
    LANGUAGE plpgsql
    AS $$
BEGIN
    -- Если цена изменилась и новая цена > 1000 рублей
    IF OLD.price IS DISTINCT FROM NEW.price AND NEW.price > 1000 THEN
        -- Автономное логирование (сохранится даже при ROLLBACK)
        PERFORM autonomous_log(NEW.bshifr, OLD.price, NEW.price);
        
        RAISE NOTICE 'Зафиксирована попытка изменения цены книги bshifr=%: % -> %', 
                     NEW.bshifr, OLD.price, NEW.price;
    END IF;
    
    RETURN NEW;
END;
$$;


ALTER FUNCTION dyachkov_ya.track_price_change() OWNER TO dyachkov_ya;

--
-- TOC entry 1841 (class 1255 OID 444522)
-- Name: update_museum_profit(); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE FUNCTION dyachkov_ya.update_museum_profit() RETURNS trigger
    LANGUAGE plpgsql
    AS $$
BEGIN
    -- Обновляем прибыль музея при добавлении нового экспоната
    UPDATE Museum
    SET profit = profit + (NEW.copy_price - NEW.creation_cost)
    WHERE id_museum = NEW.id_museum;
    
    RETURN NEW;
END;
$$;


ALTER FUNCTION dyachkov_ya.update_museum_profit() OWNER TO dyachkov_ya;

SET default_tablespace = '';

SET default_table_access_method = heap;

--
-- TOC entry 720 (class 1259 OID 450407)
-- Name: auditlog; Type: TABLE; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE TABLE dyachkov_ya.auditlog (
    id_log integer NOT NULL,
    id_user integer,
    action character varying(255),
    table_name character varying(100),
    record_id integer,
    action_time timestamp without time zone DEFAULT CURRENT_TIMESTAMP,
    ip_address character varying(45),
    details text
);


ALTER TABLE dyachkov_ya.auditlog OWNER TO dyachkov_ya;

--
-- TOC entry 719 (class 1259 OID 450406)
-- Name: auditlog_id_log_seq; Type: SEQUENCE; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE SEQUENCE dyachkov_ya.auditlog_id_log_seq
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE dyachkov_ya.auditlog_id_log_seq OWNER TO dyachkov_ya;

--
-- TOC entry 6622 (class 0 OID 0)
-- Dependencies: 719
-- Name: auditlog_id_log_seq; Type: SEQUENCE OWNED BY; Schema: dyachkov_ya; Owner: dyachkov_ya
--

ALTER SEQUENCE dyachkov_ya.auditlog_id_log_seq OWNED BY dyachkov_ya.auditlog.id_log;


--
-- TOC entry 325 (class 1259 OID 444440)
-- Name: creator; Type: TABLE; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE TABLE dyachkov_ya.creator (
    id_creator integer NOT NULL,
    full_name character varying(100) NOT NULL,
    royalty numeric(10,2),
    phone character varying(20),
    address character varying(200)
);


ALTER TABLE dyachkov_ya.creator OWNER TO dyachkov_ya;

--
-- TOC entry 327 (class 1259 OID 444460)
-- Name: exhibit; Type: TABLE; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE TABLE dyachkov_ya.exhibit (
    id_exhibit integer NOT NULL,
    type character varying(50),
    creation_date date,
    copy_price numeric(10,2),
    creation_cost numeric(10,2),
    id_creator integer,
    id_museum integer
);


ALTER TABLE dyachkov_ya.exhibit OWNER TO dyachkov_ya;

--
-- TOC entry 324 (class 1259 OID 444434)
-- Name: museum; Type: TABLE; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE TABLE dyachkov_ya.museum (
    id_museum integer NOT NULL,
    area numeric(10,2),
    profit numeric(12,2),
    phone character varying(20),
    address character varying(200)
);


ALTER TABLE dyachkov_ya.museum OWNER TO dyachkov_ya;

--
-- TOC entry 716 (class 1259 OID 450373)
-- Name: roles; Type: TABLE; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE TABLE dyachkov_ya.roles (
    id_role integer NOT NULL,
    role_name character varying(50) NOT NULL,
    description text
);


ALTER TABLE dyachkov_ya.roles OWNER TO dyachkov_ya;

--
-- TOC entry 715 (class 1259 OID 450372)
-- Name: roles_id_role_seq; Type: SEQUENCE; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE SEQUENCE dyachkov_ya.roles_id_role_seq
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE dyachkov_ya.roles_id_role_seq OWNER TO dyachkov_ya;

--
-- TOC entry 6623 (class 0 OID 0)
-- Dependencies: 715
-- Name: roles_id_role_seq; Type: SEQUENCE OWNED BY; Schema: dyachkov_ya; Owner: dyachkov_ya
--

ALTER SEQUENCE dyachkov_ya.roles_id_role_seq OWNED BY dyachkov_ya.roles.id_role;


--
-- TOC entry 718 (class 1259 OID 450386)
-- Name: users; Type: TABLE; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE TABLE dyachkov_ya.users (
    id_user integer NOT NULL,
    username character varying(50) NOT NULL,
    password_hash character varying(255) NOT NULL,
    salt character varying(100) NOT NULL,
    id_role integer NOT NULL,
    created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP,
    last_login timestamp without time zone,
    is_active boolean DEFAULT true
);


ALTER TABLE dyachkov_ya.users OWNER TO dyachkov_ya;

--
-- TOC entry 717 (class 1259 OID 450385)
-- Name: users_id_user_seq; Type: SEQUENCE; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE SEQUENCE dyachkov_ya.users_id_user_seq
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE dyachkov_ya.users_id_user_seq OWNER TO dyachkov_ya;

--
-- TOC entry 6624 (class 0 OID 0)
-- Dependencies: 717
-- Name: users_id_user_seq; Type: SEQUENCE OWNED BY; Schema: dyachkov_ya; Owner: dyachkov_ya
--

ALTER SEQUENCE dyachkov_ya.users_id_user_seq OWNED BY dyachkov_ya.users.id_user;


--
-- TOC entry 328 (class 1259 OID 444476)
-- Name: viewing; Type: TABLE; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE TABLE dyachkov_ya.viewing (
    id_ticket integer NOT NULL,
    id_exhibit integer NOT NULL,
    exhibit_rating integer,
    CONSTRAINT viewing_exhibit_rating_check CHECK (((exhibit_rating >= 1) AND (exhibit_rating <= 5)))
);


ALTER TABLE dyachkov_ya.viewing OWNER TO dyachkov_ya;

--
-- TOC entry 330 (class 1259 OID 444512)
-- Name: v_exhibit_popularity; Type: VIEW; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE VIEW dyachkov_ya.v_exhibit_popularity AS
 SELECT e.id_exhibit,
    e.type,
    count(v.id_ticket) AS views_count,
    avg(v.exhibit_rating) AS average_rating
   FROM (dyachkov_ya.exhibit e
     LEFT JOIN dyachkov_ya.viewing v ON ((e.id_exhibit = v.id_exhibit)))
  GROUP BY e.id_exhibit, e.type
  ORDER BY (avg(v.exhibit_rating)) DESC;


ALTER VIEW dyachkov_ya.v_exhibit_popularity OWNER TO dyachkov_ya;

--
-- TOC entry 329 (class 1259 OID 444507)
-- Name: v_exhibits_with_authors; Type: VIEW; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE VIEW dyachkov_ya.v_exhibits_with_authors AS
 SELECT e.id_exhibit,
    e.type,
    e.creation_date,
    e.copy_price,
    e.creation_cost,
    c.full_name AS author_name,
    m.address AS museum_location
   FROM ((dyachkov_ya.exhibit e
     LEFT JOIN dyachkov_ya.creator c ON ((e.id_creator = c.id_creator)))
     LEFT JOIN dyachkov_ya.museum m ON ((e.id_museum = m.id_museum)));


ALTER VIEW dyachkov_ya.v_exhibits_with_authors OWNER TO dyachkov_ya;

--
-- TOC entry 326 (class 1259 OID 444447)
-- Name: visitor; Type: TABLE; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE TABLE dyachkov_ya.visitor (
    id_ticket integer NOT NULL,
    full_name character varying(100) NOT NULL,
    phone character varying(20),
    visit_date date,
    museum_rating integer,
    id_museum integer,
    CONSTRAINT visitor_museum_rating_check CHECK (((museum_rating >= 1) AND (museum_rating <= 5)))
);


ALTER TABLE dyachkov_ya.visitor OWNER TO dyachkov_ya;

--
-- TOC entry 331 (class 1259 OID 444517)
-- Name: v_museum_statistics; Type: VIEW; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE VIEW dyachkov_ya.v_museum_statistics AS
 SELECT m.id_museum,
    m.address,
    count(DISTINCT e.id_exhibit) AS exhibits_count,
    count(DISTINCT v.id_ticket) AS visitors_count,
    sum(e.copy_price) AS total_exhibits_value
   FROM ((dyachkov_ya.museum m
     LEFT JOIN dyachkov_ya.exhibit e ON ((m.id_museum = e.id_museum)))
     LEFT JOIN dyachkov_ya.visitor v ON ((m.id_museum = v.id_museum)))
  GROUP BY m.id_museum, m.address;


ALTER VIEW dyachkov_ya.v_museum_statistics OWNER TO dyachkov_ya;

--
-- TOC entry 6329 (class 2604 OID 450410)
-- Name: auditlog id_log; Type: DEFAULT; Schema: dyachkov_ya; Owner: dyachkov_ya
--

ALTER TABLE ONLY dyachkov_ya.auditlog ALTER COLUMN id_log SET DEFAULT nextval('dyachkov_ya.auditlog_id_log_seq'::regclass);


--
-- TOC entry 6325 (class 2604 OID 450376)
-- Name: roles id_role; Type: DEFAULT; Schema: dyachkov_ya; Owner: dyachkov_ya
--

ALTER TABLE ONLY dyachkov_ya.roles ALTER COLUMN id_role SET DEFAULT nextval('dyachkov_ya.roles_id_role_seq'::regclass);


--
-- TOC entry 6326 (class 2604 OID 450389)
-- Name: users id_user; Type: DEFAULT; Schema: dyachkov_ya; Owner: dyachkov_ya
--

ALTER TABLE ONLY dyachkov_ya.users ALTER COLUMN id_user SET DEFAULT nextval('dyachkov_ya.users_id_user_seq'::regclass);


--
-- TOC entry 6616 (class 0 OID 450407)
-- Dependencies: 720
-- Data for Name: auditlog; Type: TABLE DATA; Schema: dyachkov_ya; Owner: dyachkov_ya
--

COPY dyachkov_ya.auditlog (id_log, id_user, action, table_name, record_id, action_time, ip_address, details) FROM stdin;
\.


--
-- TOC entry 6607 (class 0 OID 444440)
-- Dependencies: 325
-- Data for Name: creator; Type: TABLE DATA; Schema: dyachkov_ya; Owner: dyachkov_ya
--

COPY dyachkov_ya.creator (id_creator, full_name, royalty, phone, address) FROM stdin;
1	Иван Иванов	10000.00	+7-111-1111111	ул. Пушкина, 1
2	Мария Петрова	15000.00	+7-222-2222222	ул. Лермонтова, 2
3	Алексей Сидоров	12000.00	+7-333-3333333	ул. Гоголя, 3
4	Елена Васильева	18000.00	+7-444-4444444	ул. Толстого, 4
\.


--
-- TOC entry 6609 (class 0 OID 444460)
-- Dependencies: 327
-- Data for Name: exhibit; Type: TABLE DATA; Schema: dyachkov_ya; Owner: dyachkov_ya
--

COPY dyachkov_ya.exhibit (id_exhibit, type, creation_date, copy_price, creation_cost, id_creator, id_museum) FROM stdin;
101	Живопись	2020-01-15	200000.00	50000.00	1	1
102	Скульптура	2019-10-20	150000.00	40000.00	2	1
103	Графика	2021-05-10	80000.00	20000.00	1	2
104	Живопись	2018-07-22	250000.00	60000.00	3	1
105	Фотография	2022-03-15	50000.00	10000.00	2	2
106	Скульптура	2020-11-30	120000.00	35000.00	4	3
107	Икона	2017-09-05	300000.00	80000.00	1	1
108	Графика	2019-12-18	50000.00	15000.00	3	3
\.


--
-- TOC entry 6606 (class 0 OID 444434)
-- Dependencies: 324
-- Data for Name: museum; Type: TABLE DATA; Schema: dyachkov_ya; Owner: dyachkov_ya
--

COPY dyachkov_ya.museum (id_museum, area, profit, phone, address) FROM stdin;
1	1200.50	500000.00	+7-123-4567890	ул. Тверская, 5, Москва
3	1500.00	750000.00	+7-555-1234567	ул. Ленина, 15, Екатеринбург
2	800.00	400000.00	+7-987-6543210	пр. Невский, 10, Санкт-Петербург
\.


--
-- TOC entry 6612 (class 0 OID 450373)
-- Dependencies: 716
-- Data for Name: roles; Type: TABLE DATA; Schema: dyachkov_ya; Owner: dyachkov_ya
--

COPY dyachkov_ya.roles (id_role, role_name, description) FROM stdin;
1	Admin	Полный доступ ко всем функциям
2	Curator	Управление экспонатами и авторами
3	Cashier	Работа с посетителями
4	Guest	Только просмотр
\.


--
-- TOC entry 6614 (class 0 OID 450386)
-- Dependencies: 718
-- Data for Name: users; Type: TABLE DATA; Schema: dyachkov_ya; Owner: dyachkov_ya
--

COPY dyachkov_ya.users (id_user, username, password_hash, salt, id_role, created_at, last_login, is_active) FROM stdin;
9	curator	1bc936e86f9f3f3082b9e81e5489639dda3661522011f0586d74630d30aa9c2f	wkcZ1ZKs7I9Fkrhs4V6P6uM0kx0IYbY8aRyYfa06+mE=	2	2026-06-01 16:30:13.375361	\N	t
10	cashier	7f3c6eac18259fab2b0916dcd958ecbd6c5a7e1e11823fd64d23388852c57445	Yomt7dErmMWuTyE/Ut3HMN1gzzXuF9y0YFL8yVVObOU=	3	2026-06-01 16:30:13.402044	\N	t
11	guest	c09bbc66d7d00cbd91441685c4f0a23811d59d2d57754fc0b82f7271df245428	dAO2P8AgdohaItFZI4JpZ8PH/JH/AXbXJELFl4DPEmY=	4	2026-06-01 16:30:13.433068	\N	t
8	admin	119e41ff69e6c9fd2133b72169dd666a9caf9d24765483274de2730f00d85f5a	WLdeT8d1JEiq//inGEmb83MFydypm84/dldG8Bg366k=	1	2026-06-01 16:30:13.324373	2026-06-29 00:42:40.906973	t
\.


--
-- TOC entry 6610 (class 0 OID 444476)
-- Dependencies: 328
-- Data for Name: viewing; Type: TABLE DATA; Schema: dyachkov_ya; Owner: dyachkov_ya
--

COPY dyachkov_ya.viewing (id_ticket, id_exhibit, exhibit_rating) FROM stdin;
1001	101	5
1001	102	4
1001	103	5
1002	103	4
1002	105	5
1003	101	5
1003	104	4
1003	107	5
1004	106	3
1004	108	4
1005	103	5
1005	105	4
1006	101	5
1006	102	5
1006	104	4
\.


--
-- TOC entry 6608 (class 0 OID 444447)
-- Dependencies: 326
-- Data for Name: visitor; Type: TABLE DATA; Schema: dyachkov_ya; Owner: dyachkov_ya
--

COPY dyachkov_ya.visitor (id_ticket, full_name, phone, visit_date, museum_rating, id_museum) FROM stdin;
1001	Петр Сидоров	+7-123-4567890	2023-06-01	5	1
1002	Анна Ким	+7-234-5678901	2023-06-02	4	2
1003	Олег Иванов	+7-345-6789012	2023-06-03	5	1
1004	Наталья Смирнова	+7-456-7890123	2023-06-04	3	3
1005	Дмитрий Петров	+7-567-8901234	2023-06-05	4	2
1006	Екатерина Кузнецова	+7-678-9012345	2023-06-06	5	1
\.


--
-- TOC entry 6625 (class 0 OID 0)
-- Dependencies: 719
-- Name: auditlog_id_log_seq; Type: SEQUENCE SET; Schema: dyachkov_ya; Owner: dyachkov_ya
--

SELECT pg_catalog.setval('dyachkov_ya.auditlog_id_log_seq', 1, false);


--
-- TOC entry 6626 (class 0 OID 0)
-- Dependencies: 715
-- Name: roles_id_role_seq; Type: SEQUENCE SET; Schema: dyachkov_ya; Owner: dyachkov_ya
--

SELECT pg_catalog.setval('dyachkov_ya.roles_id_role_seq', 9, true);


--
-- TOC entry 6627 (class 0 OID 0)
-- Dependencies: 717
-- Name: users_id_user_seq; Type: SEQUENCE SET; Schema: dyachkov_ya; Owner: dyachkov_ya
--

SELECT pg_catalog.setval('dyachkov_ya.users_id_user_seq', 11, true);


--
-- TOC entry 6352 (class 2606 OID 450416)
-- Name: auditlog auditlog_pkey; Type: CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
--

ALTER TABLE ONLY dyachkov_ya.auditlog
    ADD CONSTRAINT auditlog_pkey PRIMARY KEY (id_log);


--
-- TOC entry 6336 (class 2606 OID 444446)
-- Name: creator creator_pkey; Type: CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
--

ALTER TABLE ONLY dyachkov_ya.creator
    ADD CONSTRAINT creator_pkey PRIMARY KEY (id_creator);


--
-- TOC entry 6340 (class 2606 OID 444465)
-- Name: exhibit exhibit_pkey; Type: CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
--

ALTER TABLE ONLY dyachkov_ya.exhibit
    ADD CONSTRAINT exhibit_pkey PRIMARY KEY (id_exhibit);


--
-- TOC entry 6334 (class 2606 OID 444439)
-- Name: museum museum_pkey; Type: CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
--

ALTER TABLE ONLY dyachkov_ya.museum
    ADD CONSTRAINT museum_pkey PRIMARY KEY (id_museum);


--
-- TOC entry 6344 (class 2606 OID 450382)
-- Name: roles roles_pkey; Type: CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
--

ALTER TABLE ONLY dyachkov_ya.roles
    ADD CONSTRAINT roles_pkey PRIMARY KEY (id_role);


--
-- TOC entry 6346 (class 2606 OID 450384)
-- Name: roles roles_role_name_key; Type: CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
--

ALTER TABLE ONLY dyachkov_ya.roles
    ADD CONSTRAINT roles_role_name_key UNIQUE (role_name);


--
-- TOC entry 6348 (class 2606 OID 450398)
-- Name: users users_pkey; Type: CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
--

ALTER TABLE ONLY dyachkov_ya.users
    ADD CONSTRAINT users_pkey PRIMARY KEY (id_user);


--
-- TOC entry 6350 (class 2606 OID 450400)
-- Name: users users_username_key; Type: CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
--

ALTER TABLE ONLY dyachkov_ya.users
    ADD CONSTRAINT users_username_key UNIQUE (username);


--
-- TOC entry 6342 (class 2606 OID 444485)
-- Name: viewing viewing_pkey; Type: CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
--

ALTER TABLE ONLY dyachkov_ya.viewing
    ADD CONSTRAINT viewing_pkey PRIMARY KEY (id_ticket, id_exhibit);


--
-- TOC entry 6338 (class 2606 OID 444454)
-- Name: visitor visitor_pkey; Type: CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
--

ALTER TABLE ONLY dyachkov_ya.visitor
    ADD CONSTRAINT visitor_pkey PRIMARY KEY (id_ticket);


--
-- TOC entry 6360 (class 2620 OID 444523)
-- Name: exhibit after_exhibit_insert; Type: TRIGGER; Schema: dyachkov_ya; Owner: dyachkov_ya
--

CREATE TRIGGER after_exhibit_insert AFTER INSERT ON dyachkov_ya.exhibit FOR EACH ROW EXECUTE FUNCTION dyachkov_ya.update_museum_profit();


--
-- TOC entry 6359 (class 2606 OID 450417)
-- Name: auditlog auditlog_id_user_fkey; Type: FK CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
--

ALTER TABLE ONLY dyachkov_ya.auditlog
    ADD CONSTRAINT auditlog_id_user_fkey FOREIGN KEY (id_user) REFERENCES dyachkov_ya.users(id_user);


--
-- TOC entry 6354 (class 2606 OID 444466)
-- Name: exhibit exhibit_id_creator_fkey; Type: FK CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
--

ALTER TABLE ONLY dyachkov_ya.exhibit
    ADD CONSTRAINT exhibit_id_creator_fkey FOREIGN KEY (id_creator) REFERENCES dyachkov_ya.creator(id_creator);


--
-- TOC entry 6355 (class 2606 OID 444471)
-- Name: exhibit exhibit_id_museum_fkey; Type: FK CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
--

ALTER TABLE ONLY dyachkov_ya.exhibit
    ADD CONSTRAINT exhibit_id_museum_fkey FOREIGN KEY (id_museum) REFERENCES dyachkov_ya.museum(id_museum);


--
-- TOC entry 6358 (class 2606 OID 450401)
-- Name: users users_id_role_fkey; Type: FK CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
--

ALTER TABLE ONLY dyachkov_ya.users
    ADD CONSTRAINT users_id_role_fkey FOREIGN KEY (id_role) REFERENCES dyachkov_ya.roles(id_role);


--
-- TOC entry 6356 (class 2606 OID 444491)
-- Name: viewing viewing_id_exhibit_fkey; Type: FK CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
--

ALTER TABLE ONLY dyachkov_ya.viewing
    ADD CONSTRAINT viewing_id_exhibit_fkey FOREIGN KEY (id_exhibit) REFERENCES dyachkov_ya.exhibit(id_exhibit);


--
-- TOC entry 6357 (class 2606 OID 444486)
-- Name: viewing viewing_id_ticket_fkey; Type: FK CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
--

ALTER TABLE ONLY dyachkov_ya.viewing
    ADD CONSTRAINT viewing_id_ticket_fkey FOREIGN KEY (id_ticket) REFERENCES dyachkov_ya.visitor(id_ticket);


--
-- TOC entry 6353 (class 2606 OID 444455)
-- Name: visitor visitor_id_museum_fkey; Type: FK CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
--

ALTER TABLE ONLY dyachkov_ya.visitor
    ADD CONSTRAINT visitor_id_museum_fkey FOREIGN KEY (id_museum) REFERENCES dyachkov_ya.museum(id_museum);


-- Completed on 2026-06-30 18:28:57 MSK

--
-- PostgreSQL database dump complete
--

\unrestrict fMX8pe7fyPeennYB6eeK17lVC7rkBp0LxzYWCFMQgMflMYdB3BYjGmqxfiz2Aj2

