dump.sql 65 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103
  1. --
  2. -- PostgreSQL database dump
  3. --
  4. \restrict fMX8pe7fyPeennYB6eeK17lVC7rkBp0LxzYWCFMQgMflMYdB3BYjGmqxfiz2Aj2
  5. -- Dumped from database version 18.0
  6. -- Dumped by pg_dump version 18.4
  7. -- Started on 2026-06-30 18:28:52 MSK
  8. SET statement_timeout = 0;
  9. SET lock_timeout = 0;
  10. SET idle_in_transaction_session_timeout = 0;
  11. SET transaction_timeout = 0;
  12. SET client_encoding = 'UTF8';
  13. SET standard_conforming_strings = on;
  14. SELECT pg_catalog.set_config('search_path', '', false);
  15. SET check_function_bodies = false;
  16. SET xmloption = content;
  17. SET client_min_messages = warning;
  18. SET row_security = off;
  19. --
  20. -- TOC entry 16 (class 2615 OID 442818)
  21. -- Name: dyachkov_ya; Type: SCHEMA; Schema: -; Owner: dyachkov_ya
  22. --
  23. CREATE SCHEMA dyachkov_ya;
  24. ALTER SCHEMA dyachkov_ya OWNER TO dyachkov_ya;
  25. --
  26. -- TOC entry 1403 (class 1255 OID 443423)
  27. -- 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
  28. --
  29. 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)
  30. LANGUAGE plpgsql
  31. AS $$
  32. DECLARE
  33. v_has_phone BOOLEAN;
  34. BEGIN
  35. BEGIN
  36. -- Проверка наличия хотя бы одного телефона
  37. v_has_phone := (p_home_phone IS NOT NULL AND p_home_phone != '') OR
  38. (p_mobile_phone IS NOT NULL AND p_mobile_phone != '');
  39. IF NOT v_has_phone THEN
  40. RAISE EXCEPTION 'Необходимо указать хотя бы один телефон (домашний или мобильный) для связи с читателем';
  41. END IF;
  42. -- Вставка пользователя
  43. INSERT INTO users (lastname, name, year_b, groups, age, category, debt, level, home_phone, mobile_phone)
  44. VALUES (p_lastname, p_name, p_year_b, p_groups, p_age, p_category, p_debt, p_level, p_home_phone, p_mobile_phone);
  45. COMMIT;
  46. RAISE NOTICE 'Пользователь "% %" успешно добавлен', p_lastname, p_name;
  47. RAISE NOTICE 'Телефоны: дом.%, моб.%',
  48. COALESCE(p_home_phone, 'не указан'),
  49. COALESCE(p_mobile_phone, 'не указан');
  50. EXCEPTION
  51. WHEN OTHERS THEN
  52. ROLLBACK;
  53. RAISE NOTICE 'ОШИБКА: %', SQLERRM;
  54. END;
  55. END;
  56. $$;
  57. 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;
  58. --
  59. -- TOC entry 1404 (class 1255 OID 443424)
  60. -- Name: authenticate_user(character varying, text); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  61. --
  62. 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)
  63. LANGUAGE plpgsql
  64. AS $$
  65. DECLARE
  66. v_user_record RECORD;
  67. v_decrypted_name TEXT;
  68. BEGIN
  69. -- Поиск пользователя
  70. SELECT u.id, u.username, u.encrypted_name, u.password_hash, r.role_name
  71. INTO v_user_record
  72. FROM system_users u
  73. JOIN roles r ON u.role_id = r.id
  74. WHERE u.username = p_username AND u.is_active = TRUE;
  75. IF v_user_record.id IS NULL THEN
  76. RETURN QUERY SELECT NULL::INTEGER, NULL::VARCHAR, NULL::TEXT, NULL::VARCHAR, FALSE::BOOLEAN;
  77. RETURN;
  78. END IF;
  79. -- Проверка пароля
  80. IF v_user_record.password_hash = crypt(p_password, v_user_record.password_hash) THEN
  81. -- Расшифровываем имя
  82. BEGIN
  83. v_decrypted_name := convert_from(decrypt(decode(v_user_record.encrypted_name, 'base64'), 'master_key', 'aes'), 'UTF8');
  84. EXCEPTION WHEN OTHERS THEN
  85. v_decrypted_name := '[Ошибка расшифровки]';
  86. END;
  87. RETURN QUERY SELECT
  88. v_user_record.id,
  89. v_user_record.username,
  90. v_decrypted_name,
  91. v_user_record.role_name,
  92. TRUE::BOOLEAN;
  93. ELSE
  94. RETURN QUERY SELECT NULL::INTEGER, NULL::VARCHAR, NULL::TEXT, NULL::VARCHAR, FALSE::BOOLEAN;
  95. END IF;
  96. END;
  97. $$;
  98. ALTER FUNCTION dyachkov_ya.authenticate_user(p_username character varying, p_password text) OWNER TO dyachkov_ya;
  99. --
  100. -- TOC entry 1405 (class 1255 OID 443425)
  101. -- Name: autonomous_log(integer, real, real); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  102. --
  103. CREATE FUNCTION dyachkov_ya.autonomous_log(p_book_bshifr integer, p_old_price real, p_new_price real) RETURNS void
  104. LANGUAGE plpgsql
  105. AS $$
  106. BEGIN
  107. -- Имитация автономной транзакции
  108. BEGIN
  109. INSERT INTO logs (bk, cena_old, cena_new)
  110. VALUES (p_book_bshifr, p_old_price, p_new_price);
  111. -- Фиксируем лог независимо от основной транзакции
  112. COMMIT;
  113. RAISE NOTICE 'Лог сохранен автономно: книга bshifr=%, цена %.2f -> %.2f',
  114. p_book_bshifr, p_old_price, p_new_price;
  115. EXCEPTION
  116. WHEN OTHERS THEN
  117. RAISE NOTICE 'Не удалось сохранить лог: %', SQLERRM;
  118. END;
  119. END;
  120. $$;
  121. ALTER FUNCTION dyachkov_ya.autonomous_log(p_book_bshifr integer, p_old_price real, p_new_price real) OWNER TO dyachkov_ya;
  122. --
  123. -- TOC entry 1406 (class 1255 OID 443426)
  124. -- Name: check_ticket_constraints(); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  125. --
  126. CREATE FUNCTION dyachkov_ya.check_ticket_constraints() RETURNS trigger
  127. LANGUAGE plpgsql
  128. AS $$
  129. DECLARE
  130. user_exists BOOLEAN;
  131. book_exists BOOLEAN;
  132. BEGIN
  133. SELECT EXISTS (SELECT 1 FROM users WHERE id = NEW.user_id)
  134. INTO user_exists;
  135. IF NOT user_exists THEN
  136. RAISE EXCEPTION 'Ошибка: Пользователь с ID % не существует в таблице users. Запись в ticket не может быть добавлена.', NEW.user_id;
  137. END IF;
  138. SELECT EXISTS (SELECT 1 FROM book WHERE bshifr = NEW.book_id)
  139. INTO book_exists;
  140. IF NOT book_exists THEN
  141. RAISE EXCEPTION 'Ошибка: Книга с шифром % не существует в таблице book. Запись в ticket не может быть добавлена.', NEW.book_id;
  142. END IF;
  143. IF NEW.date_return IS NOT NULL AND NEW.date_of_issue IS NOT NULL THEN
  144. IF NEW.date_return < NEW.date_of_issue THEN
  145. RAISE EXCEPTION 'Ошибка: Дата возврата (%) не может быть раньше даты выдачи (%).', NEW.date_return, NEW.date_of_issue;
  146. END IF;
  147. END IF;
  148. RETURN NEW;
  149. END;
  150. $$;
  151. ALTER FUNCTION dyachkov_ya.check_ticket_constraints() OWNER TO dyachkov_ya;
  152. --
  153. -- TOC entry 1407 (class 1255 OID 443427)
  154. -- Name: check_user_access(character varying, character varying); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  155. --
  156. CREATE FUNCTION dyachkov_ya.check_user_access(p_username character varying, p_required_role character varying) RETURNS boolean
  157. LANGUAGE plpgsql
  158. AS $$
  159. DECLARE
  160. v_user_role VARCHAR(50);
  161. v_has_access BOOLEAN := FALSE;
  162. BEGIN
  163. -- Начинаем транзакцию
  164. BEGIN
  165. SELECT r.role_name INTO v_user_role
  166. FROM system_users u
  167. JOIN roles r ON u.role_id = r.id
  168. WHERE u.username = p_username AND u.is_active = TRUE;
  169. -- Проверка роли (admin имеет полный доступ)
  170. IF v_user_role = 'admin' OR v_user_role = p_required_role THEN
  171. v_has_access := TRUE;
  172. END IF;
  173. -- Логируем попытку доступа (в реальной системе)
  174. INSERT INTO access_log (username, access_time, has_access, required_role)
  175. VALUES (p_username, CURRENT_TIMESTAMP, v_has_access, p_required_role);
  176. COMMIT;
  177. EXCEPTION WHEN OTHERS THEN
  178. ROLLBACK;
  179. RAISE NOTICE 'Ошибка при проверке доступа: %', SQLERRM;
  180. v_has_access := FALSE;
  181. END;
  182. RETURN v_has_access;
  183. END;
  184. $$;
  185. ALTER FUNCTION dyachkov_ya.check_user_access(p_username character varying, p_required_role character varying) OWNER TO dyachkov_ya;
  186. --
  187. -- TOC entry 1408 (class 1255 OID 443428)
  188. -- Name: check_user_by_email(text); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  189. --
  190. CREATE FUNCTION dyachkov_ya.check_user_by_email(p_email text) RETURNS integer
  191. LANGUAGE plpgsql
  192. AS $$
  193. DECLARE
  194. user_exists INTEGER;
  195. decrypted_email TEXT;
  196. user_record RECORD;
  197. BEGIN
  198. user_exists := 0;
  199. -- Проходим по всем пользователям и расшифровываем email для сравнения
  200. FOR user_record IN SELECT id, email FROM users LOOP
  201. IF user_record.email IS NOT NULL THEN
  202. BEGIN
  203. decrypted_email := decrypt_email(user_record.email);
  204. IF decrypted_email = p_email THEN
  205. user_exists := 1;
  206. EXIT;
  207. END IF;
  208. EXCEPTION WHEN OTHERS THEN
  209. -- Пропускаем ошибки дешифрования
  210. CONTINUE;
  211. END;
  212. END IF;
  213. END LOOP;
  214. RETURN user_exists;
  215. END;
  216. $$;
  217. ALTER FUNCTION dyachkov_ya.check_user_by_email(p_email text) OWNER TO dyachkov_ya;
  218. --
  219. -- TOC entry 1409 (class 1255 OID 443429)
  220. -- Name: clean_string(text); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  221. --
  222. CREATE FUNCTION dyachkov_ya.clean_string(input text) RETURNS text
  223. LANGUAGE plpgsql
  224. AS $$
  225. BEGIN
  226. IF input IS NULL THEN
  227. RETURN NULL;
  228. END IF;
  229. -- Удаление лишних пробелов, замена нескольких пробелов на один
  230. RETURN TRIM(REGEXP_REPLACE(input, '\s+', ' ', 'g'));
  231. END;
  232. $$;
  233. ALTER FUNCTION dyachkov_ya.clean_string(input text) OWNER TO dyachkov_ya;
  234. --
  235. -- TOC entry 1410 (class 1255 OID 443430)
  236. -- Name: count_books_by_user(character varying, character varying); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  237. --
  238. CREATE FUNCTION dyachkov_ya.count_books_by_user(p_lastname character varying, p_name character varying) RETURNS integer
  239. LANGUAGE plpgsql
  240. AS $$
  241. DECLARE
  242. books_count INTEGER := 0;
  243. BEGIN
  244. IF p_lastname IS NULL OR p_name IS NULL THEN
  245. RAISE EXCEPTION 'Фамилия и имя пользователя не могут быть NULL.';
  246. END IF;
  247. SELECT COUNT(t.id)
  248. INTO books_count
  249. FROM ticket t
  250. JOIN users u ON t.user_id = u.id
  251. WHERE u.lastname = p_lastname AND u.name = p_name;
  252. RETURN books_count;
  253. END;
  254. $$;
  255. ALTER FUNCTION dyachkov_ya.count_books_by_user(p_lastname character varying, p_name character varying) OWNER TO dyachkov_ya;
  256. --
  257. -- TOC entry 1411 (class 1255 OID 443431)
  258. -- Name: count_unique_readers_in_month(integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  259. --
  260. CREATE FUNCTION dyachkov_ya.count_unique_readers_in_month(p_month integer) RETURNS bigint
  261. LANGUAGE plpgsql
  262. AS $$
  263. DECLARE
  264. readers_count BIGINT := 0;
  265. BEGIN
  266. IF p_month IS NULL OR p_month < 1 OR p_month > 12 THEN
  267. RAISE EXCEPTION 'Номер месяца должен быть от 1 до 12.';
  268. END IF;
  269. SELECT COUNT(DISTINCT t.user_id)
  270. INTO readers_count
  271. FROM ticket t
  272. WHERE EXTRACT(MONTH FROM t.date_of_issue) = p_month; -- EXTRACT(MONTH FROM ...) извлекает номер месяца из даты
  273. RETURN readers_count;
  274. END;
  275. $$;
  276. ALTER FUNCTION dyachkov_ya.count_unique_readers_in_month(p_month integer) OWNER TO dyachkov_ya;
  277. --
  278. -- TOC entry 1412 (class 1255 OID 443432)
  279. -- Name: days_since_issue(integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  280. --
  281. CREATE FUNCTION dyachkov_ya.days_since_issue(p_ticket_id integer) RETURNS integer
  282. LANGUAGE plpgsql
  283. AS $$
  284. DECLARE
  285. issue_date DATE;
  286. days_elapsed INTEGER;
  287. BEGIN
  288. SELECT date_of_issue
  289. INTO issue_date
  290. FROM ticket
  291. WHERE id = p_ticket_id;
  292. IF NOT FOUND THEN
  293. RAISE EXCEPTION 'Билет с ID % не найден.', p_ticket_id;
  294. END IF;
  295. days_elapsed := Kol_Dney(issue_date, CURRENT_DATE::date);
  296. RETURN days_elapsed;
  297. END;
  298. $$;
  299. ALTER FUNCTION dyachkov_ya.days_since_issue(p_ticket_id integer) OWNER TO dyachkov_ya;
  300. --
  301. -- TOC entry 1413 (class 1255 OID 443433)
  302. -- Name: decrypt_data(text, text); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  303. --
  304. CREATE FUNCTION dyachkov_ya.decrypt_data(p_encrypted text, p_key text DEFAULT 'default_key'::text) RETURNS text
  305. LANGUAGE plpgsql
  306. AS $$
  307. DECLARE
  308. result TEXT;
  309. BEGIN
  310. result := convert_from(decrypt(decode(p_encrypted, 'hex'), p_key, 'aes'), 'UTF8');
  311. RETURN result;
  312. EXCEPTION WHEN OTHERS THEN
  313. RETURN 'Ошибка дешифрования';
  314. END;
  315. $$;
  316. ALTER FUNCTION dyachkov_ya.decrypt_data(p_encrypted text, p_key text) OWNER TO dyachkov_ya;
  317. --
  318. -- TOC entry 1414 (class 1255 OID 443435)
  319. -- Name: decrypt_email(text); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  320. --
  321. CREATE FUNCTION dyachkov_ya.decrypt_email(encrypted_email text) RETURNS text
  322. LANGUAGE plpgsql
  323. AS $$
  324. DECLARE
  325. decrypted_email TEXT;
  326. BEGIN
  327. IF encrypted_email IS NULL THEN
  328. RETURN NULL;
  329. END IF;
  330. BEGIN
  331. decrypted_email := convert_from(decrypt(decode(encrypted_email, 'base64'), 'my_secret_key', 'aes'), 'UTF8');
  332. RETURN decrypted_email;
  333. EXCEPTION WHEN OTHERS THEN
  334. RETURN encrypted_email; -- Если не зашифровано, возвращаем как есть
  335. END;
  336. END;
  337. $$;
  338. ALTER FUNCTION dyachkov_ya.decrypt_email(encrypted_email text) OWNER TO dyachkov_ya;
  339. --
  340. -- TOC entry 1415 (class 1255 OID 443436)
  341. -- Name: delete_book(integer); Type: PROCEDURE; Schema: dyachkov_ya; Owner: dyachkov_ya
  342. --
  343. CREATE PROCEDURE dyachkov_ya.delete_book(IN p_bshifr integer)
  344. LANGUAGE plpgsql
  345. AS $$
  346. DECLARE
  347. v_title VARCHAR(25);
  348. v_vidano BOOLEAN;
  349. BEGIN
  350. BEGIN
  351. -- Получаем информацию о книге
  352. SELECT title, vidano INTO v_title, v_vidano
  353. FROM book WHERE bshifr = p_bshifr;
  354. IF NOT FOUND THEN
  355. RAISE EXCEPTION 'Книга с bshifr=% не найдена', p_bshifr;
  356. END IF;
  357. -- Проверка: если книга на руках - запрещаем удаление
  358. IF v_vidano = TRUE THEN
  359. RAISE EXCEPTION 'Невозможно удалить книгу "%" - экземпляр находится на руках у читателя', v_title;
  360. END IF;
  361. -- Удаляем книгу
  362. DELETE FROM book WHERE bshifr = p_bshifr;
  363. COMMIT;
  364. RAISE NOTICE 'Книга "% (bshifr=%) успешно удалена', v_title, p_bshifr;
  365. EXCEPTION
  366. WHEN OTHERS THEN
  367. ROLLBACK;
  368. RAISE NOTICE 'ОШИБКА: %', SQLERRM;
  369. END;
  370. END;
  371. $$;
  372. ALTER PROCEDURE dyachkov_ya.delete_book(IN p_bshifr integer) OWNER TO dyachkov_ya;
  373. --
  374. -- TOC entry 1416 (class 1255 OID 443437)
  375. -- Name: delete_reader(integer); Type: PROCEDURE; Schema: dyachkov_ya; Owner: dyachkov_ya
  376. --
  377. CREATE PROCEDURE dyachkov_ya.delete_reader(IN p_user_id integer)
  378. LANGUAGE plpgsql
  379. AS $$
  380. DECLARE
  381. v_books_count INTEGER;
  382. v_username VARCHAR(50);
  383. v_books_list TEXT;
  384. BEGIN
  385. BEGIN
  386. -- Получаем имя пользователя
  387. SELECT lastname || ' ' || name INTO v_username
  388. FROM users WHERE id = p_user_id;
  389. IF NOT FOUND THEN
  390. RAISE EXCEPTION 'Пользователь с ID % не найден', p_user_id;
  391. END IF;
  392. -- Подсчет книг на руках
  393. SELECT COUNT(*) INTO v_books_count
  394. FROM ticket
  395. WHERE user_id = p_user_id
  396. AND (date_of_return IS NULL OR date_of_return > CURRENT_DATE);
  397. -- Если есть книги - формируем список и выдаем ошибку
  398. IF v_books_count > 0 THEN
  399. SELECT STRING_AGG(b.title, ', ') INTO v_books_list
  400. FROM ticket t
  401. JOIN book b ON t.book_id = b.bshifr
  402. WHERE t.user_id = p_user_id
  403. AND (t.date_of_return IS NULL OR t.date_of_return > CURRENT_DATE);
  404. RAISE EXCEPTION 'Невозможно удалить читателя "%". У него на руках % книг: %',
  405. v_username, v_books_count, v_books_list;
  406. END IF;
  407. -- Удаляем пользователя
  408. DELETE FROM users WHERE id = p_user_id;
  409. COMMIT;
  410. RAISE NOTICE 'Читатель "% (ID: %) успешно удален', v_username, p_user_id;
  411. EXCEPTION
  412. WHEN OTHERS THEN
  413. ROLLBACK;
  414. RAISE NOTICE 'ОШИБКА: %', SQLERRM;
  415. END;
  416. END;
  417. $$;
  418. ALTER PROCEDURE dyachkov_ya.delete_reader(IN p_user_id integer) OWNER TO dyachkov_ya;
  419. --
  420. -- TOC entry 1417 (class 1255 OID 443438)
  421. -- Name: encrypt_data(text, text); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  422. --
  423. CREATE FUNCTION dyachkov_ya.encrypt_data(p_data text, p_key text DEFAULT 'default_key'::text) RETURNS text
  424. LANGUAGE plpgsql
  425. AS $$
  426. BEGIN
  427. RETURN encode(encrypt(p_data::bytea, p_key, 'aes'), 'hex');
  428. END;
  429. $$;
  430. ALTER FUNCTION dyachkov_ya.encrypt_data(p_data text, p_key text) OWNER TO dyachkov_ya;
  431. --
  432. -- TOC entry 1418 (class 1255 OID 443439)
  433. -- Name: encrypt_email(); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  434. --
  435. CREATE FUNCTION dyachkov_ya.encrypt_email() RETURNS trigger
  436. LANGUAGE plpgsql
  437. AS $$
  438. BEGIN
  439. IF NEW.email IS NOT NULL AND NEW.email != '' THEN
  440. -- Используем симметричное шифрование с ключом 'secret_key'
  441. NEW.email := encode(encrypt(NEW.email::bytea, 'my_secret_key', 'aes'), 'base64');
  442. END IF;
  443. RETURN NEW;
  444. END;
  445. $$;
  446. ALTER FUNCTION dyachkov_ya.encrypt_email() OWNER TO dyachkov_ya;
  447. --
  448. -- TOC entry 1419 (class 1255 OID 443440)
  449. -- Name: generate_random_id_for_usernew(); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  450. --
  451. CREATE FUNCTION dyachkov_ya.generate_random_id_for_usernew() RETURNS trigger
  452. LANGUAGE plpgsql
  453. AS $$
  454. DECLARE
  455. new_id INTEGER;
  456. is_unique BOOLEAN := FALSE;
  457. max_attempts INTEGER := 100; -- Количество попыток генерации ID
  458. current_attempt INTEGER := 0;
  459. BEGIN
  460. -- Если ID уже предоставлен (НЕ NULL), оставляем его.
  461. IF NEW.id IS NOT NULL THEN
  462. RETURN NEW;
  463. END IF;
  464. -- Генерируем новый ID, пока он не станет уникальным.
  465. WHILE NOT is_unique LOOP
  466. -- Генерируем случайное число (диапазон 1 - 1000000).
  467. new_id := floor(random() * 1000000 + 1);
  468. -- Проверяем уникальность ID.
  469. IF NOT EXISTS (SELECT 1 FROM usernew WHERE id = new_id) THEN
  470. is_unique := TRUE;
  471. END IF;
  472. current_attempt := current_attempt + 1;
  473. -- Защита от бесконечного цикла.
  474. IF current_attempt > max_attempts THEN
  475. RAISE EXCEPTION 'Не удалось сгенерировать уникальный ID для usernew после % попыток.', max_attempts;
  476. END IF;
  477. END LOOP;
  478. -- Присваиваем сгенерированный ID.
  479. NEW.id := new_id;
  480. RETURN NEW;
  481. END;
  482. $$;
  483. ALTER FUNCTION dyachkov_ya.generate_random_id_for_usernew() OWNER TO dyachkov_ya;
  484. --
  485. -- TOC entry 1420 (class 1255 OID 443441)
  486. -- Name: generate_sentence_from_dict(integer, text); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  487. --
  488. CREATE FUNCTION dyachkov_ya.generate_sentence_from_dict(p_word_count integer, p_separator text DEFAULT ' '::text) RETURNS text
  489. LANGUAGE plpgsql
  490. AS $$
  491. DECLARE
  492. v_words TEXT[];
  493. v_sentence TEXT := '';
  494. v_capitalized_word TEXT;
  495. i INTEGER;
  496. BEGIN
  497. -- Получаем случайные слова
  498. v_words := get_random_words(p_word_count);
  499. -- Формируем предложение
  500. FOR i IN 1..array_length(v_words, 1) LOOP
  501. IF i = 1 THEN
  502. -- Первое слово с заглавной буквы
  503. v_sentence := v_sentence || initcap(v_words[i]);
  504. ELSE
  505. v_sentence := v_sentence || p_separator || lower(v_words[i]);
  506. END IF;
  507. END LOOP;
  508. -- Добавляем точку в конце
  509. v_sentence := v_sentence || '.';
  510. RETURN v_sentence;
  511. END;
  512. $$;
  513. ALTER FUNCTION dyachkov_ya.generate_sentence_from_dict(p_word_count integer, p_separator text) OWNER TO dyachkov_ya;
  514. --
  515. -- TOC entry 1421 (class 1255 OID 443442)
  516. -- Name: generate_uuid_and_time(); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  517. --
  518. CREATE FUNCTION dyachkov_ya.generate_uuid_and_time() RETURNS trigger
  519. LANGUAGE plpgsql
  520. AS $$
  521. BEGIN
  522. IF NEW.uuid IS NULL THEN
  523. NEW.uuid := gen_random_uuid();
  524. END IF;
  525. NEW.time_created := CURRENT_TIMESTAMP;
  526. RETURN NEW;
  527. END;
  528. $$;
  529. ALTER FUNCTION dyachkov_ya.generate_uuid_and_time() OWNER TO dyachkov_ya;
  530. --
  531. -- TOC entry 1849 (class 1255 OID 444742)
  532. -- Name: get_exhibit_count_by_author(integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  533. --
  534. CREATE FUNCTION dyachkov_ya.get_exhibit_count_by_author(author_id integer) RETURNS integer
  535. LANGUAGE plpgsql
  536. AS $$
  537. DECLARE
  538. exhibit_count INTEGER;
  539. BEGIN
  540. SELECT COUNT(*) INTO exhibit_count
  541. FROM Exhibit
  542. WHERE id_creator = author_id;
  543. RETURN exhibit_count;
  544. END;
  545. $$;
  546. ALTER FUNCTION dyachkov_ya.get_exhibit_count_by_author(author_id integer) OWNER TO dyachkov_ya;
  547. --
  548. -- TOC entry 1422 (class 1255 OID 443443)
  549. -- Name: get_most_expensive_book_by_author(character varying); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  550. --
  551. CREATE FUNCTION dyachkov_ya.get_most_expensive_book_by_author(p_author_lastname character varying) RETURNS character varying
  552. LANGUAGE plpgsql
  553. AS $$
  554. DECLARE
  555. book_title_result VARCHAR(255);
  556. BEGIN
  557. IF p_author_lastname IS NULL THEN
  558. RAISE EXCEPTION 'Фамилия автора не может быть NULL.';
  559. END IF;
  560. SELECT b.title
  561. INTO book_title_result
  562. FROM book b
  563. JOIN author a ON b.id_author = a.id
  564. WHERE a.lastname = p_author_lastname
  565. ORDER BY b.price DESC
  566. LIMIT 1;
  567. IF NOT FOUND THEN
  568. RAISE NOTICE 'Автор "%" не найден или у него нет книг в базе.', p_author_lastname;
  569. RETURN NULL; -- Возвращаем NULL, если ничего не найдено.
  570. END IF;
  571. RETURN book_title_result;
  572. END;
  573. $$;
  574. ALTER FUNCTION dyachkov_ya.get_most_expensive_book_by_author(p_author_lastname character varying) OWNER TO dyachkov_ya;
  575. --
  576. -- TOC entry 1423 (class 1255 OID 443444)
  577. -- Name: get_random_sentence(integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  578. --
  579. CREATE FUNCTION dyachkov_ya.get_random_sentence(word_count integer DEFAULT 5) RETURNS text
  580. LANGUAGE plpgsql
  581. AS $$
  582. DECLARE
  583. words TEXT[];
  584. sentence TEXT := '';
  585. i INTEGER;
  586. BEGIN
  587. words := get_random_words(word_count);
  588. FOR i IN 1..array_length(words, 1) LOOP
  589. IF i > 1 THEN
  590. sentence := sentence || ' ';
  591. END IF;
  592. sentence := sentence || words[i];
  593. END LOOP;
  594. RETURN sentence || '.';
  595. END;
  596. $$;
  597. ALTER FUNCTION dyachkov_ya.get_random_sentence(word_count integer) OWNER TO dyachkov_ya;
  598. --
  599. -- TOC entry 1424 (class 1255 OID 443445)
  600. -- Name: get_random_words(integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  601. --
  602. CREATE FUNCTION dyachkov_ya.get_random_words(word_count integer DEFAULT 1) RETURNS text[]
  603. LANGUAGE plpgsql
  604. AS $$
  605. DECLARE
  606. words_array TEXT[];
  607. result_array TEXT[] := '{}';
  608. i INTEGER;
  609. random_index INTEGER;
  610. BEGIN
  611. -- Пытаемся прочитать файл со словами
  612. BEGIN
  613. SELECT string_to_array(pg_read_file('/usr/share/dict/words', 0, 1000000), E'\n') INTO words_array;
  614. EXCEPTION WHEN OTHERS THEN
  615. -- Если файл не доступен, используем встроенный словарь
  616. words_array := ARRAY['apple', 'table', 'chair', 'house', 'computer', 'program', 'database', 'security', 'encryption', 'hash'];
  617. END;
  618. -- Проверяем, что массив не пустой
  619. IF array_length(words_array, 1) IS NULL THEN
  620. words_array := ARRAY['apple', 'table', 'chair', 'house', 'computer'];
  621. END IF;
  622. -- Выбираем случайные слова
  623. FOR i IN 1..word_count LOOP
  624. random_index := 1 + floor(random() * array_length(words_array, 1))::INTEGER;
  625. result_array := array_append(result_array, words_array[random_index]);
  626. END LOOP;
  627. RETURN result_array;
  628. END;
  629. $$;
  630. ALTER FUNCTION dyachkov_ya.get_random_words(word_count integer) OWNER TO dyachkov_ya;
  631. --
  632. -- TOC entry 1425 (class 1255 OID 443446)
  633. -- Name: get_ticket_details_refcursor(integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  634. --
  635. CREATE FUNCTION dyachkov_ya.get_ticket_details_refcursor(p_ticket_id integer) RETURNS refcursor
  636. LANGUAGE plpgsql
  637. AS $$
  638. DECLARE
  639. ticket_cur REFCURSOR;
  640. BEGIN
  641. IF p_ticket_id IS NULL THEN
  642. RAISE EXCEPTION 'ID билета не может быть NULL.';
  643. END IF;
  644. OPEN ticket_cur FOR
  645. SELECT
  646. u.lastname AS user_lastname,
  647. b.title AS book_title,
  648. t.date_of_issue AS ticket_date
  649. FROM ticket t
  650. JOIN users u ON t.user_id = u.id
  651. JOIN book b ON t.book_id = b.bshifr
  652. WHERE t.id = p_ticket_id;
  653. RETURN ticket_cur;
  654. END;
  655. $$;
  656. ALTER FUNCTION dyachkov_ya.get_ticket_details_refcursor(p_ticket_id integer) OWNER TO dyachkov_ya;
  657. --
  658. -- TOC entry 1838 (class 1255 OID 444504)
  659. -- Name: getaverageratingforexhibit(integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  660. --
  661. CREATE FUNCTION dyachkov_ya.getaverageratingforexhibit(exhibit_id integer) RETURNS numeric
  662. LANGUAGE plpgsql
  663. AS $$
  664. DECLARE
  665. avg_rating DECIMAL(3,2);
  666. BEGIN
  667. SELECT AVG(exhibit_rating) INTO avg_rating
  668. FROM Viewing
  669. WHERE id_exhibit = exhibit_id;
  670. RETURN COALESCE(avg_rating, 0);
  671. END;
  672. $$;
  673. ALTER FUNCTION dyachkov_ya.getaverageratingforexhibit(exhibit_id integer) OWNER TO dyachkov_ya;
  674. --
  675. -- TOC entry 1836 (class 1255 OID 444502)
  676. -- Name: getexhibitcountbyauthor(integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  677. --
  678. CREATE FUNCTION dyachkov_ya.getexhibitcountbyauthor(author_id integer) RETURNS integer
  679. LANGUAGE plpgsql
  680. AS $$
  681. DECLARE
  682. exhibit_count INT;
  683. BEGIN
  684. SELECT COUNT(*) INTO exhibit_count
  685. FROM Exhibit
  686. WHERE id_creator = author_id;
  687. RETURN exhibit_count;
  688. END;
  689. $$;
  690. ALTER FUNCTION dyachkov_ya.getexhibitcountbyauthor(author_id integer) OWNER TO dyachkov_ya;
  691. --
  692. -- TOC entry 1837 (class 1255 OID 444503)
  693. -- Name: getexhibitsbyauthor(integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  694. --
  695. 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)
  696. LANGUAGE plpgsql
  697. AS $$
  698. BEGIN
  699. RETURN QUERY
  700. SELECT e.id_exhibit, e.type, e.creation_date, e.copy_price, e.creation_cost
  701. FROM Exhibit e
  702. WHERE e.id_creator = author_id;
  703. END;
  704. $$;
  705. ALTER FUNCTION dyachkov_ya.getexhibitsbyauthor(author_id integer) OWNER TO dyachkov_ya;
  706. --
  707. -- TOC entry 1840 (class 1255 OID 444506)
  708. -- Name: getmuseumtotalvalue(integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  709. --
  710. CREATE FUNCTION dyachkov_ya.getmuseumtotalvalue(museum_id integer) RETURNS numeric
  711. LANGUAGE plpgsql
  712. AS $$
  713. DECLARE
  714. total_value DECIMAL(15,2);
  715. BEGIN
  716. SELECT SUM(e.copy_price) INTO total_value
  717. FROM Exhibit e
  718. WHERE e.id_museum = museum_id;
  719. RETURN COALESCE(total_value, 0);
  720. END;
  721. $$;
  722. ALTER FUNCTION dyachkov_ya.getmuseumtotalvalue(museum_id integer) OWNER TO dyachkov_ya;
  723. --
  724. -- TOC entry 1839 (class 1255 OID 444505)
  725. -- Name: gettop5expensiveexhibits(); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  726. --
  727. CREATE FUNCTION dyachkov_ya.gettop5expensiveexhibits() RETURNS TABLE(id_exhibit integer, type character varying, copy_price numeric, author_name character varying)
  728. LANGUAGE plpgsql
  729. AS $$
  730. BEGIN
  731. RETURN QUERY
  732. SELECT e.id_exhibit, e.type, e.copy_price, c.full_name
  733. FROM Exhibit e
  734. JOIN Creator c ON e.id_creator = c.id_creator
  735. ORDER BY e.copy_price DESC
  736. LIMIT 5;
  737. END;
  738. $$;
  739. ALTER FUNCTION dyachkov_ya.gettop5expensiveexhibits() OWNER TO dyachkov_ya;
  740. --
  741. -- TOC entry 1426 (class 1255 OID 443447)
  742. -- Name: hash_password(text, text); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  743. --
  744. CREATE FUNCTION dyachkov_ya.hash_password(p_password text, p_salt text DEFAULT NULL::text) RETURNS text
  745. LANGUAGE plpgsql
  746. AS $$
  747. DECLARE
  748. salt TEXT;
  749. hashed_password TEXT;
  750. BEGIN
  751. -- Генерируем соль, если не передана
  752. IF p_salt IS NULL THEN
  753. salt := gen_salt('bf'); -- Blowfish алгоритм
  754. ELSE
  755. salt := p_salt;
  756. END IF;
  757. -- Создаём хэш пароля
  758. hashed_password := crypt(p_password, salt);
  759. RETURN hashed_password;
  760. END;
  761. $$;
  762. ALTER FUNCTION dyachkov_ya.hash_password(p_password text, p_salt text) OWNER TO dyachkov_ya;
  763. --
  764. -- TOC entry 1427 (class 1255 OID 443448)
  765. -- Name: increase_price_by_cursor(); Type: PROCEDURE; Schema: dyachkov_ya; Owner: dyachkov_ya
  766. --
  767. CREATE PROCEDURE dyachkov_ya.increase_price_by_cursor()
  768. LANGUAGE plpgsql
  769. AS $$
  770. DECLARE
  771. v_book RECORD;
  772. v_new_price REAL;
  773. v_increase REAL := 20; -- 20%
  774. v_max_price REAL := 10000;
  775. v_processed INTEGER := 0;
  776. v_updated INTEGER := 0;
  777. BEGIN
  778. -- Курсор для книг авторов, родившихся менее 1950 года
  779. FOR v_book IN
  780. SELECT b.bshifr, b.title, b.price, a.lastname, a.name, a.year_b
  781. FROM book b
  782. JOIN author a ON b.id_author = a.id
  783. WHERE a.year_b < 1950
  784. LOOP
  785. -- Создаем точку сохранения для каждой книги
  786. PERFORM 1;
  787. BEGIN
  788. -- Вычисляем новую цену (+20%)
  789. v_new_price := v_book.price * (1 + v_increase / 100);
  790. RAISE NOTICE 'Книга: "%", Автор: % % (род. %), Цена: % -> %',
  791. v_book.title, v_book.lastname, v_book.name,
  792. v_book.year_b, v_book.price, v_new_price;
  793. -- Проверка: не превышает ли новая цена 10000
  794. IF v_new_price <= v_max_price THEN
  795. UPDATE book SET price = v_new_price WHERE bshifr = v_book.bshifr;
  796. v_updated := v_updated + 1;
  797. RAISE NOTICE ' -> ЦЕНА УВЕЛИЧЕНА';
  798. ELSE
  799. -- Цена не изменяется, просто пропускаем
  800. RAISE NOTICE ' -> ЦЕНА НЕ ИЗМЕНЕНА (%.2f превысила бы лимит %.0f)', v_new_price, v_max_price;
  801. END IF;
  802. v_processed := v_processed + 1;
  803. EXCEPTION
  804. WHEN OTHERS THEN
  805. -- При ошибке просто пропускаем книгу
  806. RAISE NOTICE ' -> ОШИБКА при обработке книги "%": %', v_book.title, SQLERRM;
  807. END;
  808. END LOOP;
  809. RAISE NOTICE '=========================================';
  810. RAISE NOTICE 'Обработано книг: %, Обновлено: %', v_processed, v_updated;
  811. RAISE NOTICE '=========================================';
  812. END;
  813. $$;
  814. ALTER PROCEDURE dyachkov_ya.increase_price_by_cursor() OWNER TO dyachkov_ya;
  815. --
  816. -- TOC entry 1428 (class 1255 OID 443449)
  817. -- Name: issue_book(integer, integer, date); Type: PROCEDURE; Schema: dyachkov_ya; Owner: dyachkov_ya
  818. --
  819. CREATE PROCEDURE dyachkov_ya.issue_book(IN p_user_id integer, IN p_book_bshifr integer, IN p_date_issue date)
  820. LANGUAGE plpgsql
  821. AS $$
  822. DECLARE
  823. v_books_count INTEGER;
  824. v_title VARCHAR(25);
  825. v_username VARCHAR(50);
  826. v_available BOOLEAN;
  827. BEGIN
  828. BEGIN
  829. -- Получаем имя пользователя
  830. SELECT lastname || ' ' || name INTO v_username
  831. FROM users WHERE id = p_user_id;
  832. IF NOT FOUND THEN
  833. RAISE EXCEPTION 'Пользователь с ID % не найден', p_user_id;
  834. END IF;
  835. -- Получаем информацию о книге
  836. SELECT title, vidano INTO v_title, v_available
  837. FROM book WHERE bshifr = p_book_bshifr;
  838. IF NOT FOUND THEN
  839. RAISE EXCEPTION 'Книга с bshifr=% не найдена', p_book_bshifr;
  840. END IF;
  841. -- Проверка доступности книги
  842. IF v_available = TRUE THEN
  843. RAISE EXCEPTION 'Книга "%" уже выдана другому читателю', v_title;
  844. END IF;
  845. -- Подсчет книг на руках у читателя
  846. SELECT COUNT(*) INTO v_books_count
  847. FROM ticket
  848. WHERE user_id = p_user_id
  849. AND (date_of_return IS NULL OR date_of_return > CURRENT_DATE);
  850. RAISE NOTICE 'У читателя "%" на руках % книг', v_username, v_books_count;
  851. -- Проверка лимита (не более 3)
  852. IF v_books_count >= 3 THEN
  853. RAISE EXCEPTION 'Читатель "%" уже имеет % книг на руках (максимум 3)',
  854. v_username, v_books_count;
  855. END IF;
  856. -- Выдача книги
  857. INSERT INTO ticket (user_id, book_id, date_of_issue, date_of_return)
  858. VALUES (p_user_id, p_book_bshifr, p_date_issue, NULL);
  859. UPDATE book SET vidano = TRUE WHERE bshifr = p_book_bshifr;
  860. COMMIT;
  861. RAISE NOTICE 'Книга "%" выдана читателю "%"', v_title, v_username;
  862. EXCEPTION
  863. WHEN OTHERS THEN
  864. ROLLBACK;
  865. RAISE NOTICE 'ОШИБКА: %', SQLERRM;
  866. END;
  867. END;
  868. $$;
  869. 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;
  870. --
  871. -- TOC entry 1429 (class 1255 OID 443450)
  872. -- Name: kol_dney(date, date); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  873. --
  874. CREATE FUNCTION dyachkov_ya.kol_dney(date1 date, date2 date) RETURNS integer
  875. LANGUAGE plpgsql
  876. AS $$
  877. DECLARE
  878. num_days INTEGER;
  879. BEGIN
  880. IF date1 IS NULL OR date2 IS NULL THEN
  881. RAISE EXCEPTION 'Даты не могут быть NULL.';
  882. END IF;
  883. -- В PostgreSQL разница между двумя DATE автоматически возвращает количество дней.
  884. num_days := date2 - date1;
  885. RETURN num_days; -- Возвращаем разницу в днях
  886. END;
  887. $$;
  888. ALTER FUNCTION dyachkov_ya.kol_dney(date1 date, date2 date) OWNER TO dyachkov_ya;
  889. --
  890. -- TOC entry 1430 (class 1255 OID 443451)
  891. -- Name: month_name_by_number(integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  892. --
  893. CREATE FUNCTION dyachkov_ya.month_name_by_number(month_num integer) RETURNS character varying
  894. LANGUAGE plpgsql
  895. AS $$
  896. BEGIN
  897. IF month_num IS NULL OR month_num < 1 OR month_num > 12 THEN
  898. RAISE EXCEPTION 'Номер месяца должен быть от 1 до 12.';
  899. END IF;
  900. RETURN CASE month_num
  901. WHEN 1 THEN 'Январь'
  902. WHEN 2 THEN 'Февраль'
  903. WHEN 3 THEN 'Март'
  904. WHEN 4 THEN 'Апрель'
  905. WHEN 5 THEN 'Май'
  906. WHEN 6 THEN 'Июнь'
  907. WHEN 7 THEN 'Июль'
  908. WHEN 8 THEN 'Август'
  909. WHEN 9 THEN 'Сентябрь'
  910. WHEN 10 THEN 'Октябрь'
  911. WHEN 11 THEN 'Ноябрь'
  912. WHEN 12 THEN 'Декабрь'
  913. ELSE 'Неизвестный месяц'
  914. END;
  915. END;
  916. $$;
  917. ALTER FUNCTION dyachkov_ya.month_name_by_number(month_num integer) OWNER TO dyachkov_ya;
  918. --
  919. -- TOC entry 1431 (class 1255 OID 443452)
  920. -- Name: multi_hash(text, integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  921. --
  922. CREATE FUNCTION dyachkov_ya.multi_hash(p_value text, p_iterations integer DEFAULT 1) RETURNS text
  923. LANGUAGE plpgsql
  924. AS $$
  925. DECLARE
  926. hashed_value TEXT;
  927. i INTEGER;
  928. BEGIN
  929. IF p_value IS NULL THEN
  930. RETURN NULL;
  931. END IF;
  932. hashed_value := p_value;
  933. FOR i IN 1..p_iterations LOOP
  934. hashed_value := encode(digest(hashed_value, 'sha256'), 'hex');
  935. END LOOP;
  936. RETURN hashed_value;
  937. END;
  938. $$;
  939. ALTER FUNCTION dyachkov_ya.multi_hash(p_value text, p_iterations integer) OWNER TO dyachkov_ya;
  940. --
  941. -- TOC entry 1432 (class 1255 OID 443453)
  942. -- Name: normalize_region(text); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  943. --
  944. CREATE FUNCTION dyachkov_ya.normalize_region(region_name text) RETURNS text
  945. LANGUAGE plpgsql
  946. AS $$
  947. BEGIN
  948. RETURN CASE
  949. WHEN region_name ILIKE '%Санкт-Петербург%' OR region_name ILIKE '%СПб%' THEN 'Санкт-Петербург'
  950. WHEN region_name ILIKE '%Ленинградская%' THEN 'Ленинградская область'
  951. WHEN region_name ILIKE '%Новгород%' THEN 'Новгородская область'
  952. ELSE clean_string(region_name)
  953. END;
  954. END;
  955. $$;
  956. ALTER FUNCTION dyachkov_ya.normalize_region(region_name text) OWNER TO dyachkov_ya;
  957. --
  958. -- TOC entry 1433 (class 1255 OID 443454)
  959. -- Name: nvl(anyelement, anyelement); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  960. --
  961. CREATE FUNCTION dyachkov_ya.nvl(input_value anyelement, default_value anyelement) RETURNS anyelement
  962. LANGUAGE plpgsql
  963. AS $$
  964. BEGIN
  965. RETURN COALESCE(input_value, default_value);
  966. END;
  967. $$;
  968. ALTER FUNCTION dyachkov_ya.nvl(input_value anyelement, default_value anyelement) OWNER TO dyachkov_ya;
  969. --
  970. -- TOC entry 1434 (class 1255 OID 443455)
  971. -- Name: parse_salary(text); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  972. --
  973. CREATE FUNCTION dyachkov_ya.parse_salary(salary_text text) RETURNS TABLE(min_salary numeric, max_salary numeric)
  974. LANGUAGE plpgsql
  975. AS $$
  976. DECLARE
  977. numbers NUMERIC[];
  978. BEGIN
  979. IF salary_text IS NULL THEN
  980. min_salary := NULL;
  981. max_salary := NULL;
  982. RETURN NEXT;
  983. RETURN;
  984. END IF;
  985. -- Извлечение чисел из строки
  986. SELECT ARRAY(
  987. SELECT REGEXP_MATCHES(salary_text, '(\d+[.,]?\d*)', 'g')
  988. ) INTO numbers;
  989. IF array_length(numbers, 1) >= 1 THEN
  990. min_salary := numbers[1]::NUMERIC;
  991. IF array_length(numbers, 1) >= 2 THEN
  992. max_salary := numbers[2]::NUMERIC;
  993. ELSE
  994. max_salary := min_salary;
  995. END IF;
  996. ELSE
  997. min_salary := NULL;
  998. max_salary := NULL;
  999. END IF;
  1000. RETURN NEXT;
  1001. END;
  1002. $$;
  1003. ALTER FUNCTION dyachkov_ya.parse_salary(salary_text text) OWNER TO dyachkov_ya;
  1004. --
  1005. -- TOC entry 1435 (class 1255 OID 443456)
  1006. -- Name: proizv(integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  1007. --
  1008. CREATE FUNCTION dyachkov_ya.proizv(n integer) RETURNS bigint
  1009. LANGUAGE plpgsql
  1010. AS $$
  1011. DECLARE
  1012. i INTEGER;
  1013. total_product BIGINT := 1; -- Инициализируем произведение единицей
  1014. BEGIN
  1015. IF n IS NULL OR n <= 0 THEN
  1016. RAISE EXCEPTION 'Параметр n должен быть положительным целым числом.';
  1017. END IF;
  1018. -- Цикл от 1 до n
  1019. FOR i IN 1..n LOOP
  1020. total_product := total_product * i; -- Умножаем текущее число на произведение
  1021. END LOOP;
  1022. RETURN total_product; -- Возвращаем вычисленное произведение
  1023. END;
  1024. $$;
  1025. ALTER FUNCTION dyachkov_ya.proizv(n integer) OWNER TO dyachkov_ya;
  1026. --
  1027. -- TOC entry 1436 (class 1255 OID 443457)
  1028. -- Name: proverka(integer, integer, date, date); Type: PROCEDURE; Schema: dyachkov_ya; Owner: dyachkov_ya
  1029. --
  1030. CREATE PROCEDURE dyachkov_ya.proverka(IN kodu integer, IN kodb integer, IN dvid date, IN dvoz date)
  1031. LANGUAGE plpgsql
  1032. AS $$
  1033. DECLARE
  1034. rez VARCHAR(10) := 'ОК';
  1035. pr INTEGER;
  1036. v_last_id INTEGER;
  1037. BEGIN
  1038. -- Начинаем транзакцию
  1039. BEGIN
  1040. -- Ввод записи в таблицу ticket (она же bilet)
  1041. INSERT INTO ticket (user_id, book_id, date_of_issue, date_of_return)
  1042. VALUES (kodU, kodB, dVid, dVoz)
  1043. RETURNING id INTO v_last_id;
  1044. RAISE NOTICE 'Вставлена запись с ID: %', v_last_id;
  1045. -- Вычисляем разницу между датой возврата и датой выдачи
  1046. SELECT (date_of_return - date_of_issue) INTO pr
  1047. FROM ticket WHERE id = v_last_id;
  1048. RAISE NOTICE 'Разница между датами: % дней', pr;
  1049. -- Проверка: если разница > 0, то фиксируем, иначе откатываем
  1050. IF pr > 0 THEN
  1051. COMMIT;
  1052. rez := 'ОК';
  1053. RAISE NOTICE 'Дата возврата корректна. Транзакция зафиксирована.';
  1054. ELSE
  1055. ROLLBACK;
  1056. rez := 'No';
  1057. RAISE NOTICE 'ОШИБКА: дата возврата (%) меньше или равна дате выдачи (%)', dVoz, dVid;
  1058. RAISE NOTICE 'Транзакция откачена.';
  1059. END IF;
  1060. -- Выводим значение переменной rez
  1061. RAISE NOTICE 'Результат: %', rez;
  1062. EXCEPTION
  1063. WHEN OTHERS THEN
  1064. ROLLBACK;
  1065. rez := 'Error';
  1066. RAISE NOTICE 'Ошибка при выполнении: %', SQLERRM;
  1067. END;
  1068. END;
  1069. $$;
  1070. ALTER PROCEDURE dyachkov_ya.proverka(IN kodu integer, IN kodb integer, IN dvid date, IN dvoz date) OWNER TO dyachkov_ya;
  1071. --
  1072. -- TOC entry 1437 (class 1255 OID 443458)
  1073. -- Name: register_user(character varying, text, text, character varying); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  1074. --
  1075. 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
  1076. LANGUAGE plpgsql
  1077. AS $$
  1078. DECLARE
  1079. v_salt TEXT;
  1080. v_role_id INTEGER;
  1081. v_encrypted_name TEXT;
  1082. v_user_id INTEGER;
  1083. BEGIN
  1084. -- Получаем ID роли
  1085. SELECT id INTO v_role_id FROM roles WHERE role_name = p_role_name;
  1086. IF v_role_id IS NULL THEN
  1087. RAISE EXCEPTION 'Роль "%" не существует', p_role_name;
  1088. END IF;
  1089. -- Генерируем соль
  1090. v_salt := gen_salt('bf');
  1091. -- Шифруем имя пользователя (используем AES)
  1092. v_encrypted_name := encode(encrypt(p_name::bytea, 'master_key', 'aes'), 'base64');
  1093. -- Вставляем пользователя
  1094. INSERT INTO system_users (username, encrypted_name, password_hash, salt, role_id)
  1095. VALUES (p_username, v_encrypted_name, crypt(p_password, v_salt), v_salt, v_role_id)
  1096. RETURNING id INTO v_user_id;
  1097. RETURN v_user_id;
  1098. EXCEPTION WHEN unique_violation THEN
  1099. RAISE EXCEPTION 'Пользователь с именем "%" уже существует', p_username;
  1100. END;
  1101. $$;
  1102. 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;
  1103. --
  1104. -- TOC entry 1438 (class 1255 OID 443459)
  1105. -- Name: summa(integer); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  1106. --
  1107. CREATE FUNCTION dyachkov_ya.summa(n integer) RETURNS bigint
  1108. LANGUAGE plpgsql
  1109. AS $$
  1110. DECLARE
  1111. i INTEGER;
  1112. total_sum BIGINT := 0; -- Инициализируем сумму нулем
  1113. BEGIN
  1114. IF n IS NULL OR n <= 0 THEN
  1115. RAISE EXCEPTION 'Параметр n должен быть положительным целым числом.';
  1116. END IF;
  1117. -- Цикл от 1 до n
  1118. FOR i IN 1..n LOOP
  1119. total_sum := total_sum + i; -- Добавляем текущее число к сумме
  1120. END LOOP;
  1121. RETURN total_sum; -- Возвращаем вычисленную сумму
  1122. END;
  1123. $$;
  1124. ALTER FUNCTION dyachkov_ya.summa(n integer) OWNER TO dyachkov_ya;
  1125. --
  1126. -- TOC entry 1439 (class 1255 OID 443460)
  1127. -- Name: tek_vr(integer); Type: PROCEDURE; Schema: dyachkov_ya; Owner: dyachkov_ya
  1128. --
  1129. CREATE PROCEDURE dyachkov_ya.tek_vr(IN n integer)
  1130. LANGUAGE plpgsql
  1131. AS $$
  1132. DECLARE
  1133. i INTEGER;
  1134. BEGIN
  1135. IF n IS NULL OR n <= 0 THEN
  1136. RAISE EXCEPTION 'Параметр N должен быть положительным числом.';
  1137. END IF;
  1138. RAISE NOTICE '--- Вывод текущего времени % раз ---', n;
  1139. FOR i IN 1..n LOOP
  1140. -- NOW() возвращает текущую дату и время
  1141. RAISE NOTICE 'Итерация %: Текущее время: %', i, NOW();
  1142. END LOOP;
  1143. END;
  1144. $$;
  1145. ALTER PROCEDURE dyachkov_ya.tek_vr(IN n integer) OWNER TO dyachkov_ya;
  1146. --
  1147. -- TOC entry 1440 (class 1255 OID 443461)
  1148. -- Name: ticket_insert_trigger(); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  1149. --
  1150. CREATE FUNCTION dyachkov_ya.ticket_insert_trigger() RETURNS trigger
  1151. LANGUAGE plpgsql
  1152. AS $$
  1153. BEGIN
  1154. IF ( NEW.date_of_issue >= DATE '2024-01-01' AND NEW.date_of_issue < DATE '2024-02-01' ) THEN INSERT INTO ticket2024m1 VALUES (NEW.*);
  1155. ELSIF ( NEW.date_of_issue >= DATE '2024-02-01' AND NEW.date_of_issue < DATE '2024-03-01' ) THEN INSERT INTO ticket2024m2 VALUES (NEW.*);
  1156. ELSIF ( NEW.date_of_issue >= DATE '2024-03-01' AND NEW.date_of_issue < DATE '2024-04-01' ) THEN INSERT INTO ticket2024m3 VALUES (NEW.*);
  1157. ELSIF ( NEW.date_of_issue >= DATE '2024-04-01' AND NEW.date_of_issue < DATE '2024-05-01' ) THEN INSERT INTO ticket2024m4 VALUES (NEW.*);
  1158. ELSIF ( NEW.date_of_issue >= DATE '2024-05-01' AND NEW.date_of_issue < DATE '2024-06-01' ) THEN INSERT INTO ticket2024m5 VALUES (NEW.*);
  1159. ELSIF ( NEW.date_of_issue >= DATE '2024-06-01' AND NEW.date_of_issue < DATE '2024-07-01' ) THEN INSERT INTO ticket2024m6 VALUES (NEW.*);
  1160. ELSIF ( NEW.date_of_issue >= DATE '2024-07-01' AND NEW.date_of_issue < DATE '2024-08-01' ) THEN INSERT INTO ticket2024m7 VALUES (NEW.*);
  1161. ELSIF ( NEW.date_of_issue >= DATE '2024-08-01' AND NEW.date_of_issue < DATE '2024-09-01' ) THEN INSERT INTO ticket2024m8 VALUES (NEW.*);
  1162. ELSIF ( NEW.date_of_issue >= DATE '2024-09-01' AND NEW.date_of_issue < DATE '2024-10-01' ) THEN INSERT INTO ticket2024m9 VALUES (NEW.*);
  1163. ELSIF ( NEW.date_of_issue >= DATE '2024-10-01' AND NEW.date_of_issue < DATE '2024-11-01' ) THEN INSERT INTO ticket2024m10 VALUES (NEW.*);
  1164. ELSIF ( NEW.date_of_issue >= DATE '2024-11-01' AND NEW.date_of_issue < DATE '2024-12-01' ) THEN INSERT INTO ticket2024m11 VALUES (NEW.*);
  1165. ELSIF ( NEW.date_of_issue >= DATE '2024-12-01' AND NEW.date_of_issue < DATE '2025-01-01' ) THEN INSERT INTO ticket2024m12 VALUES (NEW.*);
  1166. ELSE RAISE EXCEPTION 'Date out of range for all partitions';
  1167. END IF;
  1168. RETURN NULL;
  1169. END;
  1170. $$;
  1171. ALTER FUNCTION dyachkov_ya.ticket_insert_trigger() OWNER TO dyachkov_ya;
  1172. --
  1173. -- TOC entry 1441 (class 1255 OID 443462)
  1174. -- Name: track_price_change(); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  1175. --
  1176. CREATE FUNCTION dyachkov_ya.track_price_change() RETURNS trigger
  1177. LANGUAGE plpgsql
  1178. AS $$
  1179. BEGIN
  1180. -- Если цена изменилась и новая цена > 1000 рублей
  1181. IF OLD.price IS DISTINCT FROM NEW.price AND NEW.price > 1000 THEN
  1182. -- Автономное логирование (сохранится даже при ROLLBACK)
  1183. PERFORM autonomous_log(NEW.bshifr, OLD.price, NEW.price);
  1184. RAISE NOTICE 'Зафиксирована попытка изменения цены книги bshifr=%: % -> %',
  1185. NEW.bshifr, OLD.price, NEW.price;
  1186. END IF;
  1187. RETURN NEW;
  1188. END;
  1189. $$;
  1190. ALTER FUNCTION dyachkov_ya.track_price_change() OWNER TO dyachkov_ya;
  1191. --
  1192. -- TOC entry 1841 (class 1255 OID 444522)
  1193. -- Name: update_museum_profit(); Type: FUNCTION; Schema: dyachkov_ya; Owner: dyachkov_ya
  1194. --
  1195. CREATE FUNCTION dyachkov_ya.update_museum_profit() RETURNS trigger
  1196. LANGUAGE plpgsql
  1197. AS $$
  1198. BEGIN
  1199. -- Обновляем прибыль музея при добавлении нового экспоната
  1200. UPDATE Museum
  1201. SET profit = profit + (NEW.copy_price - NEW.creation_cost)
  1202. WHERE id_museum = NEW.id_museum;
  1203. RETURN NEW;
  1204. END;
  1205. $$;
  1206. ALTER FUNCTION dyachkov_ya.update_museum_profit() OWNER TO dyachkov_ya;
  1207. SET default_tablespace = '';
  1208. SET default_table_access_method = heap;
  1209. --
  1210. -- TOC entry 720 (class 1259 OID 450407)
  1211. -- Name: auditlog; Type: TABLE; Schema: dyachkov_ya; Owner: dyachkov_ya
  1212. --
  1213. CREATE TABLE dyachkov_ya.auditlog (
  1214. id_log integer NOT NULL,
  1215. id_user integer,
  1216. action character varying(255),
  1217. table_name character varying(100),
  1218. record_id integer,
  1219. action_time timestamp without time zone DEFAULT CURRENT_TIMESTAMP,
  1220. ip_address character varying(45),
  1221. details text
  1222. );
  1223. ALTER TABLE dyachkov_ya.auditlog OWNER TO dyachkov_ya;
  1224. --
  1225. -- TOC entry 719 (class 1259 OID 450406)
  1226. -- Name: auditlog_id_log_seq; Type: SEQUENCE; Schema: dyachkov_ya; Owner: dyachkov_ya
  1227. --
  1228. CREATE SEQUENCE dyachkov_ya.auditlog_id_log_seq
  1229. AS integer
  1230. START WITH 1
  1231. INCREMENT BY 1
  1232. NO MINVALUE
  1233. NO MAXVALUE
  1234. CACHE 1;
  1235. ALTER SEQUENCE dyachkov_ya.auditlog_id_log_seq OWNER TO dyachkov_ya;
  1236. --
  1237. -- TOC entry 6622 (class 0 OID 0)
  1238. -- Dependencies: 719
  1239. -- Name: auditlog_id_log_seq; Type: SEQUENCE OWNED BY; Schema: dyachkov_ya; Owner: dyachkov_ya
  1240. --
  1241. ALTER SEQUENCE dyachkov_ya.auditlog_id_log_seq OWNED BY dyachkov_ya.auditlog.id_log;
  1242. --
  1243. -- TOC entry 325 (class 1259 OID 444440)
  1244. -- Name: creator; Type: TABLE; Schema: dyachkov_ya; Owner: dyachkov_ya
  1245. --
  1246. CREATE TABLE dyachkov_ya.creator (
  1247. id_creator integer NOT NULL,
  1248. full_name character varying(100) NOT NULL,
  1249. royalty numeric(10,2),
  1250. phone character varying(20),
  1251. address character varying(200)
  1252. );
  1253. ALTER TABLE dyachkov_ya.creator OWNER TO dyachkov_ya;
  1254. --
  1255. -- TOC entry 327 (class 1259 OID 444460)
  1256. -- Name: exhibit; Type: TABLE; Schema: dyachkov_ya; Owner: dyachkov_ya
  1257. --
  1258. CREATE TABLE dyachkov_ya.exhibit (
  1259. id_exhibit integer NOT NULL,
  1260. type character varying(50),
  1261. creation_date date,
  1262. copy_price numeric(10,2),
  1263. creation_cost numeric(10,2),
  1264. id_creator integer,
  1265. id_museum integer
  1266. );
  1267. ALTER TABLE dyachkov_ya.exhibit OWNER TO dyachkov_ya;
  1268. --
  1269. -- TOC entry 324 (class 1259 OID 444434)
  1270. -- Name: museum; Type: TABLE; Schema: dyachkov_ya; Owner: dyachkov_ya
  1271. --
  1272. CREATE TABLE dyachkov_ya.museum (
  1273. id_museum integer NOT NULL,
  1274. area numeric(10,2),
  1275. profit numeric(12,2),
  1276. phone character varying(20),
  1277. address character varying(200)
  1278. );
  1279. ALTER TABLE dyachkov_ya.museum OWNER TO dyachkov_ya;
  1280. --
  1281. -- TOC entry 716 (class 1259 OID 450373)
  1282. -- Name: roles; Type: TABLE; Schema: dyachkov_ya; Owner: dyachkov_ya
  1283. --
  1284. CREATE TABLE dyachkov_ya.roles (
  1285. id_role integer NOT NULL,
  1286. role_name character varying(50) NOT NULL,
  1287. description text
  1288. );
  1289. ALTER TABLE dyachkov_ya.roles OWNER TO dyachkov_ya;
  1290. --
  1291. -- TOC entry 715 (class 1259 OID 450372)
  1292. -- Name: roles_id_role_seq; Type: SEQUENCE; Schema: dyachkov_ya; Owner: dyachkov_ya
  1293. --
  1294. CREATE SEQUENCE dyachkov_ya.roles_id_role_seq
  1295. AS integer
  1296. START WITH 1
  1297. INCREMENT BY 1
  1298. NO MINVALUE
  1299. NO MAXVALUE
  1300. CACHE 1;
  1301. ALTER SEQUENCE dyachkov_ya.roles_id_role_seq OWNER TO dyachkov_ya;
  1302. --
  1303. -- TOC entry 6623 (class 0 OID 0)
  1304. -- Dependencies: 715
  1305. -- Name: roles_id_role_seq; Type: SEQUENCE OWNED BY; Schema: dyachkov_ya; Owner: dyachkov_ya
  1306. --
  1307. ALTER SEQUENCE dyachkov_ya.roles_id_role_seq OWNED BY dyachkov_ya.roles.id_role;
  1308. --
  1309. -- TOC entry 718 (class 1259 OID 450386)
  1310. -- Name: users; Type: TABLE; Schema: dyachkov_ya; Owner: dyachkov_ya
  1311. --
  1312. CREATE TABLE dyachkov_ya.users (
  1313. id_user integer NOT NULL,
  1314. username character varying(50) NOT NULL,
  1315. password_hash character varying(255) NOT NULL,
  1316. salt character varying(100) NOT NULL,
  1317. id_role integer NOT NULL,
  1318. created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP,
  1319. last_login timestamp without time zone,
  1320. is_active boolean DEFAULT true
  1321. );
  1322. ALTER TABLE dyachkov_ya.users OWNER TO dyachkov_ya;
  1323. --
  1324. -- TOC entry 717 (class 1259 OID 450385)
  1325. -- Name: users_id_user_seq; Type: SEQUENCE; Schema: dyachkov_ya; Owner: dyachkov_ya
  1326. --
  1327. CREATE SEQUENCE dyachkov_ya.users_id_user_seq
  1328. AS integer
  1329. START WITH 1
  1330. INCREMENT BY 1
  1331. NO MINVALUE
  1332. NO MAXVALUE
  1333. CACHE 1;
  1334. ALTER SEQUENCE dyachkov_ya.users_id_user_seq OWNER TO dyachkov_ya;
  1335. --
  1336. -- TOC entry 6624 (class 0 OID 0)
  1337. -- Dependencies: 717
  1338. -- Name: users_id_user_seq; Type: SEQUENCE OWNED BY; Schema: dyachkov_ya; Owner: dyachkov_ya
  1339. --
  1340. ALTER SEQUENCE dyachkov_ya.users_id_user_seq OWNED BY dyachkov_ya.users.id_user;
  1341. --
  1342. -- TOC entry 328 (class 1259 OID 444476)
  1343. -- Name: viewing; Type: TABLE; Schema: dyachkov_ya; Owner: dyachkov_ya
  1344. --
  1345. CREATE TABLE dyachkov_ya.viewing (
  1346. id_ticket integer NOT NULL,
  1347. id_exhibit integer NOT NULL,
  1348. exhibit_rating integer,
  1349. CONSTRAINT viewing_exhibit_rating_check CHECK (((exhibit_rating >= 1) AND (exhibit_rating <= 5)))
  1350. );
  1351. ALTER TABLE dyachkov_ya.viewing OWNER TO dyachkov_ya;
  1352. --
  1353. -- TOC entry 330 (class 1259 OID 444512)
  1354. -- Name: v_exhibit_popularity; Type: VIEW; Schema: dyachkov_ya; Owner: dyachkov_ya
  1355. --
  1356. CREATE VIEW dyachkov_ya.v_exhibit_popularity AS
  1357. SELECT e.id_exhibit,
  1358. e.type,
  1359. count(v.id_ticket) AS views_count,
  1360. avg(v.exhibit_rating) AS average_rating
  1361. FROM (dyachkov_ya.exhibit e
  1362. LEFT JOIN dyachkov_ya.viewing v ON ((e.id_exhibit = v.id_exhibit)))
  1363. GROUP BY e.id_exhibit, e.type
  1364. ORDER BY (avg(v.exhibit_rating)) DESC;
  1365. ALTER VIEW dyachkov_ya.v_exhibit_popularity OWNER TO dyachkov_ya;
  1366. --
  1367. -- TOC entry 329 (class 1259 OID 444507)
  1368. -- Name: v_exhibits_with_authors; Type: VIEW; Schema: dyachkov_ya; Owner: dyachkov_ya
  1369. --
  1370. CREATE VIEW dyachkov_ya.v_exhibits_with_authors AS
  1371. SELECT e.id_exhibit,
  1372. e.type,
  1373. e.creation_date,
  1374. e.copy_price,
  1375. e.creation_cost,
  1376. c.full_name AS author_name,
  1377. m.address AS museum_location
  1378. FROM ((dyachkov_ya.exhibit e
  1379. LEFT JOIN dyachkov_ya.creator c ON ((e.id_creator = c.id_creator)))
  1380. LEFT JOIN dyachkov_ya.museum m ON ((e.id_museum = m.id_museum)));
  1381. ALTER VIEW dyachkov_ya.v_exhibits_with_authors OWNER TO dyachkov_ya;
  1382. --
  1383. -- TOC entry 326 (class 1259 OID 444447)
  1384. -- Name: visitor; Type: TABLE; Schema: dyachkov_ya; Owner: dyachkov_ya
  1385. --
  1386. CREATE TABLE dyachkov_ya.visitor (
  1387. id_ticket integer NOT NULL,
  1388. full_name character varying(100) NOT NULL,
  1389. phone character varying(20),
  1390. visit_date date,
  1391. museum_rating integer,
  1392. id_museum integer,
  1393. CONSTRAINT visitor_museum_rating_check CHECK (((museum_rating >= 1) AND (museum_rating <= 5)))
  1394. );
  1395. ALTER TABLE dyachkov_ya.visitor OWNER TO dyachkov_ya;
  1396. --
  1397. -- TOC entry 331 (class 1259 OID 444517)
  1398. -- Name: v_museum_statistics; Type: VIEW; Schema: dyachkov_ya; Owner: dyachkov_ya
  1399. --
  1400. CREATE VIEW dyachkov_ya.v_museum_statistics AS
  1401. SELECT m.id_museum,
  1402. m.address,
  1403. count(DISTINCT e.id_exhibit) AS exhibits_count,
  1404. count(DISTINCT v.id_ticket) AS visitors_count,
  1405. sum(e.copy_price) AS total_exhibits_value
  1406. FROM ((dyachkov_ya.museum m
  1407. LEFT JOIN dyachkov_ya.exhibit e ON ((m.id_museum = e.id_museum)))
  1408. LEFT JOIN dyachkov_ya.visitor v ON ((m.id_museum = v.id_museum)))
  1409. GROUP BY m.id_museum, m.address;
  1410. ALTER VIEW dyachkov_ya.v_museum_statistics OWNER TO dyachkov_ya;
  1411. --
  1412. -- TOC entry 6329 (class 2604 OID 450410)
  1413. -- Name: auditlog id_log; Type: DEFAULT; Schema: dyachkov_ya; Owner: dyachkov_ya
  1414. --
  1415. ALTER TABLE ONLY dyachkov_ya.auditlog ALTER COLUMN id_log SET DEFAULT nextval('dyachkov_ya.auditlog_id_log_seq'::regclass);
  1416. --
  1417. -- TOC entry 6325 (class 2604 OID 450376)
  1418. -- Name: roles id_role; Type: DEFAULT; Schema: dyachkov_ya; Owner: dyachkov_ya
  1419. --
  1420. ALTER TABLE ONLY dyachkov_ya.roles ALTER COLUMN id_role SET DEFAULT nextval('dyachkov_ya.roles_id_role_seq'::regclass);
  1421. --
  1422. -- TOC entry 6326 (class 2604 OID 450389)
  1423. -- Name: users id_user; Type: DEFAULT; Schema: dyachkov_ya; Owner: dyachkov_ya
  1424. --
  1425. ALTER TABLE ONLY dyachkov_ya.users ALTER COLUMN id_user SET DEFAULT nextval('dyachkov_ya.users_id_user_seq'::regclass);
  1426. --
  1427. -- TOC entry 6616 (class 0 OID 450407)
  1428. -- Dependencies: 720
  1429. -- Data for Name: auditlog; Type: TABLE DATA; Schema: dyachkov_ya; Owner: dyachkov_ya
  1430. --
  1431. COPY dyachkov_ya.auditlog (id_log, id_user, action, table_name, record_id, action_time, ip_address, details) FROM stdin;
  1432. \.
  1433. --
  1434. -- TOC entry 6607 (class 0 OID 444440)
  1435. -- Dependencies: 325
  1436. -- Data for Name: creator; Type: TABLE DATA; Schema: dyachkov_ya; Owner: dyachkov_ya
  1437. --
  1438. COPY dyachkov_ya.creator (id_creator, full_name, royalty, phone, address) FROM stdin;
  1439. 1 Иван Иванов 10000.00 +7-111-1111111 ул. Пушкина, 1
  1440. 2 Мария Петрова 15000.00 +7-222-2222222 ул. Лермонтова, 2
  1441. 3 Алексей Сидоров 12000.00 +7-333-3333333 ул. Гоголя, 3
  1442. 4 Елена Васильева 18000.00 +7-444-4444444 ул. Толстого, 4
  1443. \.
  1444. --
  1445. -- TOC entry 6609 (class 0 OID 444460)
  1446. -- Dependencies: 327
  1447. -- Data for Name: exhibit; Type: TABLE DATA; Schema: dyachkov_ya; Owner: dyachkov_ya
  1448. --
  1449. COPY dyachkov_ya.exhibit (id_exhibit, type, creation_date, copy_price, creation_cost, id_creator, id_museum) FROM stdin;
  1450. 101 Живопись 2020-01-15 200000.00 50000.00 1 1
  1451. 102 Скульптура 2019-10-20 150000.00 40000.00 2 1
  1452. 103 Графика 2021-05-10 80000.00 20000.00 1 2
  1453. 104 Живопись 2018-07-22 250000.00 60000.00 3 1
  1454. 105 Фотография 2022-03-15 50000.00 10000.00 2 2
  1455. 106 Скульптура 2020-11-30 120000.00 35000.00 4 3
  1456. 107 Икона 2017-09-05 300000.00 80000.00 1 1
  1457. 108 Графика 2019-12-18 50000.00 15000.00 3 3
  1458. \.
  1459. --
  1460. -- TOC entry 6606 (class 0 OID 444434)
  1461. -- Dependencies: 324
  1462. -- Data for Name: museum; Type: TABLE DATA; Schema: dyachkov_ya; Owner: dyachkov_ya
  1463. --
  1464. COPY dyachkov_ya.museum (id_museum, area, profit, phone, address) FROM stdin;
  1465. 1 1200.50 500000.00 +7-123-4567890 ул. Тверская, 5, Москва
  1466. 3 1500.00 750000.00 +7-555-1234567 ул. Ленина, 15, Екатеринбург
  1467. 2 800.00 400000.00 +7-987-6543210 пр. Невский, 10, Санкт-Петербург
  1468. \.
  1469. --
  1470. -- TOC entry 6612 (class 0 OID 450373)
  1471. -- Dependencies: 716
  1472. -- Data for Name: roles; Type: TABLE DATA; Schema: dyachkov_ya; Owner: dyachkov_ya
  1473. --
  1474. COPY dyachkov_ya.roles (id_role, role_name, description) FROM stdin;
  1475. 1 Admin Полный доступ ко всем функциям
  1476. 2 Curator Управление экспонатами и авторами
  1477. 3 Cashier Работа с посетителями
  1478. 4 Guest Только просмотр
  1479. \.
  1480. --
  1481. -- TOC entry 6614 (class 0 OID 450386)
  1482. -- Dependencies: 718
  1483. -- Data for Name: users; Type: TABLE DATA; Schema: dyachkov_ya; Owner: dyachkov_ya
  1484. --
  1485. COPY dyachkov_ya.users (id_user, username, password_hash, salt, id_role, created_at, last_login, is_active) FROM stdin;
  1486. 9 curator 1bc936e86f9f3f3082b9e81e5489639dda3661522011f0586d74630d30aa9c2f wkcZ1ZKs7I9Fkrhs4V6P6uM0kx0IYbY8aRyYfa06+mE= 2 2026-06-01 16:30:13.375361 \N t
  1487. 10 cashier 7f3c6eac18259fab2b0916dcd958ecbd6c5a7e1e11823fd64d23388852c57445 Yomt7dErmMWuTyE/Ut3HMN1gzzXuF9y0YFL8yVVObOU= 3 2026-06-01 16:30:13.402044 \N t
  1488. 11 guest c09bbc66d7d00cbd91441685c4f0a23811d59d2d57754fc0b82f7271df245428 dAO2P8AgdohaItFZI4JpZ8PH/JH/AXbXJELFl4DPEmY= 4 2026-06-01 16:30:13.433068 \N t
  1489. 8 admin 119e41ff69e6c9fd2133b72169dd666a9caf9d24765483274de2730f00d85f5a WLdeT8d1JEiq//inGEmb83MFydypm84/dldG8Bg366k= 1 2026-06-01 16:30:13.324373 2026-06-29 00:42:40.906973 t
  1490. \.
  1491. --
  1492. -- TOC entry 6610 (class 0 OID 444476)
  1493. -- Dependencies: 328
  1494. -- Data for Name: viewing; Type: TABLE DATA; Schema: dyachkov_ya; Owner: dyachkov_ya
  1495. --
  1496. COPY dyachkov_ya.viewing (id_ticket, id_exhibit, exhibit_rating) FROM stdin;
  1497. 1001 101 5
  1498. 1001 102 4
  1499. 1001 103 5
  1500. 1002 103 4
  1501. 1002 105 5
  1502. 1003 101 5
  1503. 1003 104 4
  1504. 1003 107 5
  1505. 1004 106 3
  1506. 1004 108 4
  1507. 1005 103 5
  1508. 1005 105 4
  1509. 1006 101 5
  1510. 1006 102 5
  1511. 1006 104 4
  1512. \.
  1513. --
  1514. -- TOC entry 6608 (class 0 OID 444447)
  1515. -- Dependencies: 326
  1516. -- Data for Name: visitor; Type: TABLE DATA; Schema: dyachkov_ya; Owner: dyachkov_ya
  1517. --
  1518. COPY dyachkov_ya.visitor (id_ticket, full_name, phone, visit_date, museum_rating, id_museum) FROM stdin;
  1519. 1001 Петр Сидоров +7-123-4567890 2023-06-01 5 1
  1520. 1002 Анна Ким +7-234-5678901 2023-06-02 4 2
  1521. 1003 Олег Иванов +7-345-6789012 2023-06-03 5 1
  1522. 1004 Наталья Смирнова +7-456-7890123 2023-06-04 3 3
  1523. 1005 Дмитрий Петров +7-567-8901234 2023-06-05 4 2
  1524. 1006 Екатерина Кузнецова +7-678-9012345 2023-06-06 5 1
  1525. \.
  1526. --
  1527. -- TOC entry 6625 (class 0 OID 0)
  1528. -- Dependencies: 719
  1529. -- Name: auditlog_id_log_seq; Type: SEQUENCE SET; Schema: dyachkov_ya; Owner: dyachkov_ya
  1530. --
  1531. SELECT pg_catalog.setval('dyachkov_ya.auditlog_id_log_seq', 1, false);
  1532. --
  1533. -- TOC entry 6626 (class 0 OID 0)
  1534. -- Dependencies: 715
  1535. -- Name: roles_id_role_seq; Type: SEQUENCE SET; Schema: dyachkov_ya; Owner: dyachkov_ya
  1536. --
  1537. SELECT pg_catalog.setval('dyachkov_ya.roles_id_role_seq', 9, true);
  1538. --
  1539. -- TOC entry 6627 (class 0 OID 0)
  1540. -- Dependencies: 717
  1541. -- Name: users_id_user_seq; Type: SEQUENCE SET; Schema: dyachkov_ya; Owner: dyachkov_ya
  1542. --
  1543. SELECT pg_catalog.setval('dyachkov_ya.users_id_user_seq', 11, true);
  1544. --
  1545. -- TOC entry 6352 (class 2606 OID 450416)
  1546. -- Name: auditlog auditlog_pkey; Type: CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
  1547. --
  1548. ALTER TABLE ONLY dyachkov_ya.auditlog
  1549. ADD CONSTRAINT auditlog_pkey PRIMARY KEY (id_log);
  1550. --
  1551. -- TOC entry 6336 (class 2606 OID 444446)
  1552. -- Name: creator creator_pkey; Type: CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
  1553. --
  1554. ALTER TABLE ONLY dyachkov_ya.creator
  1555. ADD CONSTRAINT creator_pkey PRIMARY KEY (id_creator);
  1556. --
  1557. -- TOC entry 6340 (class 2606 OID 444465)
  1558. -- Name: exhibit exhibit_pkey; Type: CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
  1559. --
  1560. ALTER TABLE ONLY dyachkov_ya.exhibit
  1561. ADD CONSTRAINT exhibit_pkey PRIMARY KEY (id_exhibit);
  1562. --
  1563. -- TOC entry 6334 (class 2606 OID 444439)
  1564. -- Name: museum museum_pkey; Type: CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
  1565. --
  1566. ALTER TABLE ONLY dyachkov_ya.museum
  1567. ADD CONSTRAINT museum_pkey PRIMARY KEY (id_museum);
  1568. --
  1569. -- TOC entry 6344 (class 2606 OID 450382)
  1570. -- Name: roles roles_pkey; Type: CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
  1571. --
  1572. ALTER TABLE ONLY dyachkov_ya.roles
  1573. ADD CONSTRAINT roles_pkey PRIMARY KEY (id_role);
  1574. --
  1575. -- TOC entry 6346 (class 2606 OID 450384)
  1576. -- Name: roles roles_role_name_key; Type: CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
  1577. --
  1578. ALTER TABLE ONLY dyachkov_ya.roles
  1579. ADD CONSTRAINT roles_role_name_key UNIQUE (role_name);
  1580. --
  1581. -- TOC entry 6348 (class 2606 OID 450398)
  1582. -- Name: users users_pkey; Type: CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
  1583. --
  1584. ALTER TABLE ONLY dyachkov_ya.users
  1585. ADD CONSTRAINT users_pkey PRIMARY KEY (id_user);
  1586. --
  1587. -- TOC entry 6350 (class 2606 OID 450400)
  1588. -- Name: users users_username_key; Type: CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
  1589. --
  1590. ALTER TABLE ONLY dyachkov_ya.users
  1591. ADD CONSTRAINT users_username_key UNIQUE (username);
  1592. --
  1593. -- TOC entry 6342 (class 2606 OID 444485)
  1594. -- Name: viewing viewing_pkey; Type: CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
  1595. --
  1596. ALTER TABLE ONLY dyachkov_ya.viewing
  1597. ADD CONSTRAINT viewing_pkey PRIMARY KEY (id_ticket, id_exhibit);
  1598. --
  1599. -- TOC entry 6338 (class 2606 OID 444454)
  1600. -- Name: visitor visitor_pkey; Type: CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
  1601. --
  1602. ALTER TABLE ONLY dyachkov_ya.visitor
  1603. ADD CONSTRAINT visitor_pkey PRIMARY KEY (id_ticket);
  1604. --
  1605. -- TOC entry 6360 (class 2620 OID 444523)
  1606. -- Name: exhibit after_exhibit_insert; Type: TRIGGER; Schema: dyachkov_ya; Owner: dyachkov_ya
  1607. --
  1608. CREATE TRIGGER after_exhibit_insert AFTER INSERT ON dyachkov_ya.exhibit FOR EACH ROW EXECUTE FUNCTION dyachkov_ya.update_museum_profit();
  1609. --
  1610. -- TOC entry 6359 (class 2606 OID 450417)
  1611. -- Name: auditlog auditlog_id_user_fkey; Type: FK CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
  1612. --
  1613. ALTER TABLE ONLY dyachkov_ya.auditlog
  1614. ADD CONSTRAINT auditlog_id_user_fkey FOREIGN KEY (id_user) REFERENCES dyachkov_ya.users(id_user);
  1615. --
  1616. -- TOC entry 6354 (class 2606 OID 444466)
  1617. -- Name: exhibit exhibit_id_creator_fkey; Type: FK CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
  1618. --
  1619. ALTER TABLE ONLY dyachkov_ya.exhibit
  1620. ADD CONSTRAINT exhibit_id_creator_fkey FOREIGN KEY (id_creator) REFERENCES dyachkov_ya.creator(id_creator);
  1621. --
  1622. -- TOC entry 6355 (class 2606 OID 444471)
  1623. -- Name: exhibit exhibit_id_museum_fkey; Type: FK CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
  1624. --
  1625. ALTER TABLE ONLY dyachkov_ya.exhibit
  1626. ADD CONSTRAINT exhibit_id_museum_fkey FOREIGN KEY (id_museum) REFERENCES dyachkov_ya.museum(id_museum);
  1627. --
  1628. -- TOC entry 6358 (class 2606 OID 450401)
  1629. -- Name: users users_id_role_fkey; Type: FK CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
  1630. --
  1631. ALTER TABLE ONLY dyachkov_ya.users
  1632. ADD CONSTRAINT users_id_role_fkey FOREIGN KEY (id_role) REFERENCES dyachkov_ya.roles(id_role);
  1633. --
  1634. -- TOC entry 6356 (class 2606 OID 444491)
  1635. -- Name: viewing viewing_id_exhibit_fkey; Type: FK CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
  1636. --
  1637. ALTER TABLE ONLY dyachkov_ya.viewing
  1638. ADD CONSTRAINT viewing_id_exhibit_fkey FOREIGN KEY (id_exhibit) REFERENCES dyachkov_ya.exhibit(id_exhibit);
  1639. --
  1640. -- TOC entry 6357 (class 2606 OID 444486)
  1641. -- Name: viewing viewing_id_ticket_fkey; Type: FK CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
  1642. --
  1643. ALTER TABLE ONLY dyachkov_ya.viewing
  1644. ADD CONSTRAINT viewing_id_ticket_fkey FOREIGN KEY (id_ticket) REFERENCES dyachkov_ya.visitor(id_ticket);
  1645. --
  1646. -- TOC entry 6353 (class 2606 OID 444455)
  1647. -- Name: visitor visitor_id_museum_fkey; Type: FK CONSTRAINT; Schema: dyachkov_ya; Owner: dyachkov_ya
  1648. --
  1649. ALTER TABLE ONLY dyachkov_ya.visitor
  1650. ADD CONSTRAINT visitor_id_museum_fkey FOREIGN KEY (id_museum) REFERENCES dyachkov_ya.museum(id_museum);
  1651. -- Completed on 2026-06-30 18:28:57 MSK
  1652. --
  1653. -- PostgreSQL database dump complete
  1654. --
  1655. \unrestrict fMX8pe7fyPeennYB6eeK17lVC7rkBp0LxzYWCFMQgMflMYdB3BYjGmqxfiz2Aj2