Logo Море(!) аналитической информации!
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware
Архив форумов ЦИТФорума
Море(!) вопросов - Море(!) ответов
 
 FAQFAQ   ПоискПоиск   ПользователиПользователи   ГруппыГруппы   РегистрацияРегистрация 
 ПрофильПрофиль   Войти и проверить личные сообщенияВойти и проверить личные сообщения   ВходВход 
Как правильно задавать вопросы

pl/pgsql, тревиальная задача

 
Перейти:  
Этот форум закрыт, вы не можете писать новые сообщения и редактировать старые.   Эта тема закрыта, вы не можете писать ответы и редактировать сообщения.    Список форумов Архив форумов ЦИТФорума -> Базы данных
Предыдущая тема :: Следующая тема  
Автор Сообщение
=Fluf=



Зарегистрирован: 17.11.2005
Сообщения: 4

СообщениеДобавлено: Вс Мар 25 2007 18:53    Заголовок сообщения: pl/pgsql, тревиальная задача Ответить с цитатой

В m$sql есть функция nest_level(). она выдаёт уровень вложенности кода.

Я хочу решить тривиальную задачу на PostgreSQL.

Есть таблица tb0. на ней висит триггер tr0, который ведёт на триггерную функцию tf0. она добавляет некую строку в другую таблицу tb1 и возвращает NEW.

В целях соблюдения правила целостности данных, я хочу запритить инсерты, апдейты и делеты в таблицу tb1 со всех мест, кроме триггерной функции tf0, или других триггерных функций или процедур.

В m$ можно было бы повелить на эту таблицу tb1 триггер tr1 и триггерную функцию tf1, которая при срабатывании смотрела бы уровень вложенности когда. Так, если встретиться insetr into tb1 в триггерной функции tf0, то при выполнении функции nest_level() в триггерной функции tf1 мы получим 2. (Сам не пробавал, но так в документации написано =) m$ неузаю... ) ) А если бы исерт был напрямую из запроса, в таблицу tb1, то nest_level() в tf1 выдал бы 1.

Мне надо сделать нечто подобное в pgsql. А именно мне надо из кода в tf1 как либо узнать, был ли запущен триггер tr1 внешним запросом или он сработал из-за инсерта/апдейта/делета, совершённого из другой триггерной функции/хранимой процедуры.


====== Сам вопрос ========

Я уверен, что все вы решали эту задачу, но возможно совершенно другим потём. Материализую задание для понимания.

Это банальное написание лога.
Предположим есть таблица main и log. При добавлении в строки в main, автоматически заноситься запись в таблицу log, что такой то юзведь добавил строку в main. Если удалить строку из main - она удалиться, и в log автоматически запишеться, что такой то юзверь удалил строку из main.

Если кто то сделает инсерт в таблицу log о том, что некая строка в main была удалена, а на самом то деле её никто не удалял - получиться нарушение целостности данных.

Как это предотвратить??
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
критикан



Зарегистрирован: 18.02.2005
Сообщения: 247

СообщениеДобавлено: Вт Апр 17 2007 10:41    Заголовок сообщения: зачем слону два хвоста? Ответить с цитатой

есть определённые сомнения в необходимости учёта уровня вложенности для контроля целостности. относительно вопроса о соответствии таблицы и лога: если в логе появятся подряд идущие записи "insert" и "delete", является ли это нарушением целостности? думаю -- нет. поэтому исходный вопрос относится не целостности базы данных, а к достоверности информации в ней, а это решается цифровой подписью, а не уровнем вложенности триггера
----------------
зачем слону два хвоста?
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
=Fluf=



Зарегистрирован: 17.11.2005
Сообщения: 4

СообщениеДобавлено: Вт Апр 17 2007 20:30    Заголовок сообщения: Ответить с цитатой

Хм, ну под целостностью данных в БД как раз и подразумевается непротипоречивость данных в разных частях БД (в разных таблицах). О достоверности речи не идёт.
Черь идёт о возможности грубой ошибки работы администратора (последующего суппорта).
Приведу наиболее простой пример.
В моей БД на некоторые таблицы вообще нельзя делать delete. В таблицы содержатся некие диапазоны бланков. А так же логин того, кто сделал запись. Удаление записи делается insert-ом, и вводить надо тот же диапазон, но с отрицательным знаком, атак же логин и пароль. Триггер проверяет логин и пароль, а затем делает delete соответствующего диапазона. Пользователю, а он же нерадивый администратор, делать delete самому нельзя.
Как мне поставить такой запрет?

Слишком долго расказывать все подробности моего приложения. Но суть такова - мне надо, что бы из некой таблицы всякий триггер пог сделать delete или update. А пользователь - нет.
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
критикан



Зарегистрирован: 18.02.2005
Сообщения: 247

СообщениеДобавлено: Пт Апр 20 2007 16:57    Заголовок сообщения: Танк запросто вспашет поле, но зачем трактористу танк? Ответить с цитатой

Под "целостностью" я тоже понимаю "непротипоречивость", а под "достоверностью" я понимаю уверенность в том, что "данное действие было произведено в данный момент времени данным пользователем с данным информативным смыслом".

Пример следующий: пусть есть таблица-инфо, содержащая ссылку на таблицу-справочник, предназначенный именно для таблицы-инфо.

структура таблицы-инфо: код, количество в штуках
структура таблицы-справочника: код, наименование

ситуация, когда имеет место:

-- целостность+достоверность (всё хорошо):
содержимое таблицы-инфо: 5, 15
содержимое таблицы-справочника: 5, 'стул'

-- нецелостность+достоверность (в справочнике отсутствует запись с кодом 5):
содержимое таблицы-инфо: 5, 15
содержимое таблицы-справочника: 4, 'стул'

-- целостность+недостоверность (воздух в штуках не измеряют, но СУБД об этом не знает, поэтому целостность не нарушена, а для потребителей это бессмыслица, поэтому информация недостоверна):
содержимое таблицы-инфо: 5, 15
содержимое таблицы-справочника: 5, 'воздух'

-- нецелостность+недостоверность (всё плохо):
содержимое таблицы-инфо: 5, 15
содержимое таблицы-справочника: 4, 'воздух'


Что касается вопроса о запрете удаления записей, то эта задача решается разделением функции администрирования на "администратора безопасности" и "администратора содержимого". "Администратору содержимого" (он же нерадивый администратор) ставят запрет на, в частности, прямое управление записями, а дают права на специальные процедуры, предназначенные для администрирования содержимого. Сами процедуры, естественно, должны быть сделаны так, чтобы не допускать нарушений безопасности -- в данном случае они должны вместо удаления выполнять ввод записей с отрицательным знаком.
------------------
Танк запросто вспашет поле, но зачем трактористу танк?
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
=Fluf=



Зарегистрирован: 17.11.2005
Сообщения: 4

СообщениеДобавлено: Пт Апр 20 2007 21:10    Заголовок сообщения: Ответить с цитатой

@@@@@
"Администратору содержимого" (он же нерадивый администратор) ставят запрет на, в частности, прямое управление записями, а дают права на специальные процедуры, предназначенные для администрирования содержимого
@@@@@

Так в этом то весь и вопрос - как это сделать??! С другими БД не было вопросов, но как это сделать менно в PostgreSQL??!! Ведь привелегии тут unix-образные, т.е. если пользователь не может делать делете из таблицы, то и запускаемая от его имени хранимаю процедура этот делет сделать тоже не сможет. Вот я сейчас написал таблицу, хранимую процедуру (только взял не делет а инсерт), запрос и вывод (запрос выполнен от пользователя 'math_user'):


######################
############## Таблица:
######################

CREATE TABLE math.qwe
(
q boolean NOT NULL,
CONSTRAINT qwe_pkey PRIMARY KEY (q)
)
WITHOUT OIDS;
ALTER TABLE math.qwe OWNER TO postgres;



#######################
####### Хранимая процедура:
#######################

CREATE OR REPLACE FUNCTION math.f_qwe()
RETURNS boolean AS
$BODY$begin
insert into math.qwe values (true);
return null;
end;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;
ALTER FUNCTION math.f_qwe() OWNER TO postgres;
GRANT EXECUTE ON FUNCTION math.f_qwe() TO math_user;



####################
####### Запрос и вывод:
####################

select math.f_qwe();

ERROR: permission denied for relation qwe
SQL state: 42501
Context: SQL statement "INSERT INTO math.qwe values (true)"
PL/pgSQL function "f_qwe" line 2 at SQL statement
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
критикан



Зарегистрирован: 18.02.2005
Сообщения: 247

СообщениеДобавлено: Пн Апр 23 2007 09:39    Заголовок сообщения: Если нет сохи, то почему бы не воспользоваться плугом? Ответить с цитатой

Я с самим постгрессом не баловался, поэтому сразу не скажу, какие команды нужно дать, а общая идея -- запускать эти спецпроцедуры не от имени ограниченного пользователя (он же нерадивый админ), а от имени пользователя с большими правами. Наверняка, эта возможность имеется, и скорее всего она выглядит так: владельцем спецпроцедуры является пользователь с большими правами, а исполнять её может пользователь с маленькими правами. Во всяком случае, если постгресс придерживается политики юниксов в отношении прав, то в нём реализовано право, аналогичное атрибуту SUID, то есть право исполнения от имени владельца команды, а не от имени запускающего.

Итого: нужно поискать в пострессе опции запуска от имени другого пользователя
----------------
Если нет сохи, то почему бы не воспользоваться плугом?
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
gray_hemp



Зарегистрирован: 13.05.2007
Сообщения: 1

СообщениеДобавлено: Вс Май 13 2007 18:17    Заголовок сообщения: Re: pl/pgsql, тревиальная задача Ответить с цитатой

Код:
-- Главная таблица

CREATE TABLE main
(
  id serial NOT NULL,
  field1 varchar,
  CONSTRAINT main_id PRIMARY KEY (id)
)
WITHOUT OIDS;
ALTER TABLE main OWNER TO postgres;

-- Все могут всё

GRANT ALL ON TABLE main TO postgres;
GRANT ALL ON TABLE main TO public;

GRANT ALL ON TABLE main_id_seq TO postgres;
GRANT ALL ON TABLE main_id_seq TO public;

-- Лог для главной таблицы

CREATE TABLE log
(
  id int4 NOT NULL,
  field1 varchar,
  log_op varchar, -- операция (insert/update/delete)
  log_id serial NOT NULL,
  log_user varchar DEFAULT "session_user"(), -- ! тут обязательно session_user, объясню ниже
  log_timestamp timestamp DEFAULT now(),
  CONSTRAINT log_pkey PRIMARY KEY (log_id)
)
WITHOUT OIDS;
ALTER TABLE log OWNER TO postgres;

-- postgres может всё, другие только читать

GRANT ALL ON TABLE log TO postgres;
GRANT SELECT ON TABLE log TO public;

GRANT ALL ON TABLE log_log_id_seq TO postgres;

-- Собственно функция логирования, причём логирует только изменённые поля

CREATE OR REPLACE FUNCTION tr_logmain()
  RETURNS "trigger" AS
$BODY$declare
  changes main%rowtype;
begin
  if TG_OP = 'INSERT' then
    changes := new; -- при добавлении логируем все поля
  elsif TG_OP = 'UPDATE' then
    -- при обновлении
    changes.id := old.id; -- идентифицирующие логируем всегда
    changes.field1 := nullif(new.field1, old.field1); -- для других только изменения
  else
    changes.id := old.id; -- при удалении только идентифицирующие
  end if;

  insert into log select changes.*;
  update log set log_op = TG_OP where log_id = lastval();
 
  if TG_OP = 'INSERT' or TG_OP = 'UPDATE' then
    return new;
  else
    return null;
  end if;
end;$BODY$
  LANGUAGE 'plpgsql' VOLATILE SECURITY DEFINER;
  -- SECURITY DEFINER - выполняется с привелегиями создателя, т.е. postgres
  -- поэтому используем session_user (см. выше)
ALTER FUNCTION tr_logmain() OWNER TO postgres;

CREATE TRIGGER tr_logmain_aiud
  AFTER INSERT OR UPDATE OR DELETE
  ON main
  FOR EACH ROW
  EXECUTE PROCEDURE tr_logmain();

-- А теперь тестик (выполнять под обычным юзером)
/*
insert into main (field1) values ('aaa');
update main set field1 = 'bbb';
update main set field1 = 'bbb';
update main set field1 = 'ccc';
delete from main where field1 = 'ccc';
insert into main (field1) values ('ddd');
update main set field1 = 'eee';
update main set field1 = 'fff';
update main set field1 = 'fff';
delete from main where field1 = 'fff';
*/
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
Показать сообщения:   
Этот форум закрыт, вы не можете писать новые сообщения и редактировать старые.   Эта тема закрыта, вы не можете писать ответы и редактировать сообщения.    Список форумов Архив форумов ЦИТФорума -> Базы данных Часовой пояс: GMT + 3
Страница 1 из 1

 
Перейти:  
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах


Powered by phpBB © 2001, 2002 phpBB Group
Русская поддержка phpBB

 

IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

Информация для рекламодателей PR-акции, размещение рекламы — adv@citforum.ru,
тел. +7 495 6608306, ICQ 232284597
Пресс-релизы — pr@citforum.ru
Послать комментарий
Информация для авторов
This Web server launched on February 24, 1997
Copyright © 1997-2000 CIT, © 2001-2006 CIT Forum
Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...