Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Firebird, InterBase Новый топик    Ответить
 Логирование изменений  [new]
romero111
Member

Откуда:
Сообщений: 6
Добрый день.
Опишу задачу: необходимо логировать данные в БД, пока только удаление. Знаю, что в IBExpert есть своя штука для этого. Но хочется под себя. Чтобы написанный один единственный триггер / процедуру можно было размножить на все таблицы с минимальными изменениями самого триггера / процедуры. Созданы две таблицы LOG_TABLES, LOG_FIELDS.
Алгоритм решения: из системных таблиц нахожу все поля конкретной таблицы, для которой хочу после удаления из нее записи сделать лог в таблицах логирования. Значение old для каждого поля пишем в таблицу логирования. Все.
Проблема: хочу к контекстной переменной Old добавить названия полей и именно это значение писать в лог-таблицу. Т.е. неким образом превратить ее опять в контекстную после конкатенации и выполнить запись. Возможно это?

:context_old_value = 'old.'||lower(:field_name);
:deleted_value = :context_old_value;
s = 'insert into LOG_FIELDS (LOG_TABLE_ID,FIELD_NAME, FIELD_TYPE, OLD_VALUE) values (?,?,?,?)';
execute statement (:s) (:sequence_id,:field_name,:type_data,:deleted_value)

Записывает он здесь, конечно, как текст.
12 сен 19, 15:42    [21969589]     Ответить | Цитировать Сообщить модератору
 Re: Логирование изменений  [new]
Симонов Денис
Member

Откуда: Рязань
Сообщений: 9831
romero111,

создай себе процедуру которая автоматически будет генерировать текст логирующего триггера для произвольной таблицы.
Потом выполни эту ХП для всех нужных таблиц из результатов собери скрипт. Это не сложно.
12 сен 19, 15:59    [21969607]     Ответить | Цитировать Сообщить модератору
 Re: Логирование изменений  [new]
Мимопроходящий
Member

Откуда: бурятский тундрюк, эсквайр
Сообщений: 30321

1. нужно учитывать NULL-ы
2. вещественные числа

Posted via ActualForum NNTP Server 1.5

12 сен 19, 16:03    [21969614]     Ответить | Цитировать Сообщить модератору
 Re: Логирование изменений  [new]
romero111
Member

Откуда:
Сообщений: 6
я и собираюсь составить некий текст триггера. Но пробела в том, что я соберу все названия полей таблицы: пусть 'field1', 'field2', 'field3'. Присобачу к OLD это имя - и это уже будет текст, а не контекстная переменная.
В переменной ins_field_value = названия поля таблицы = 'field1'.
insert into log_table (field_name,flield_value) values ('field1','old.'||ins_field_value )
Он вставить запись в flield_value как текст = 'old.field1'. Мне же надо, что он взял как контекстную переменную этот параметр и вставил туда значение поля field1.
12 сен 19, 16:12    [21969626]     Ответить | Цитировать Сообщить модератору
 Re: Логирование изменений  [new]
Dimitry Sibiryakov
Member

Откуда:
Сообщений: 48163

romero111
я и собираюсь составить некий текст триггера.

Обломись. Не может быть "универсального протоколирующего триггера".

Posted via ActualForum NNTP Server 1.5

12 сен 19, 16:16    [21969629]     Ответить | Цитировать Сообщить модератору
 Re: Логирование изменений  [new]
Симонов Денис
Member

Откуда: Рязань
Сообщений: 9831
romero111,

тебе говорят собирай текст триггера целиком как строку и скармливай её выполнителю скрипта
12 сен 19, 16:33    [21969647]     Ответить | Цитировать Сообщить модератору
 Re: Логирование изменений  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 3969
Dimitry Sibiryakov
romero111
я и собираюсь составить некий текст триггера.

Обломись. Не может быть "универсального протоколирующего триггера".
Ну почему же.
Такая задача, и многие другие, уже решены здесь:
http://button.dekel.ru/
12 сен 19, 21:05    [21969891]     Ответить | Цитировать Сообщить модератору
 Re: Логирование изменений  [new]
romero111
Member

Откуда:
Сообщений: 6
Симонов Денис, процка создана (где входящие параметры Таблица и Операция). Создается длиннющая строка текста триггера. Но проблема то этим не решилась: я ее (строку) вставляю в выполнитель скриптов, но последняя моя операция в этом скрипте, как и описано в самом первом сообщении, никак не преобразилась. Т.е. она осталась текстовым полем, а мне ее надо скормить как old.field_name, а не как 'old.field_name'.
Задача: я беру все поля таблицы и хочу записать их значения при удалении из таблицы в таблицу лога. Делать хочу это в триггере на before_delete. Где есть контекстная переменная OLD. Хочу к ней в цикле (или как хотите называйте) присобачивать по очереди названия полей и получать значение, которые записывать в лог. С присобавчиванием (конкатенацией) проблем нет, есть проблема, что эта переменная уже не является контекстной и не выполняет свои "функции", а просто превратилась в текст.
13 сен 19, 10:06    [21970124]     Ответить | Цитировать Сообщить модератору
 Re: Логирование изменений  [new]
KreatorXXI
Member

Откуда: Москва
Сообщений: 783
romero111,

"execute statement" не выполняет скрипт? Или что?
13 сен 19, 10:40    [21970150]     Ответить | Цитировать Сообщить модератору
 Re: Логирование изменений  [new]
Симонов Денис
Member

Откуда: Рязань
Сообщений: 9831
romero111,

ещё раз объясняю. Так сделать нельзя. Поля после OLD надо указывать в явном виде. Т.е. создать универсальный триггер не получится, но можно сделать процедуру которая облегчит написание таких триггеров.
Вот кусок моего пакета для записи логов. Тебе он не подойдёт, но ты можешь уловить мысль

  PROCEDURE CREATE_UPDATE_TRIGGER(ATable VARCHAR(31)) RETURNS (SQL_TEXT BLOB SUB_TYPE TEXT)
  AS
    DECLARE EOL CHAR(2);
    DECLARE PK_FIELDNAME VARCHAR(31);
  BEGIN
    ATable = TRIM(ATable);
    SELECT
      TRIM(IND.RDB$FIELD_NAME) AS FIELD_NAME
    FROM RDB$RELATION_CONSTRAINTS RC
      JOIN RDB$INDEX_SEGMENTS IND ON IND.RDB$INDEX_NAME = RC.RDB$INDEX_NAME
    WHERE RC.RDB$RELATION_NAME = :ATable AND RC.RDB$CONSTRAINT_TYPE = 'PRIMARY KEY'
    INTO PK_FIELDNAME;

    EOL = ASCII_CHAR(13) || ASCII_CHAR(10);
    SQL_TEXT = 'CREATE OR ALTER TRIGGER TR_' || ATable || '_REPL_AU FOR ' || ATable || EOL;
    SQL_TEXT = SQL_TEXT || 'ACTIVE AFTER UPDATE POSITION 0' || EOL;
    SQL_TEXT = SQL_TEXT || 'AS' || EOL;
    SQL_TEXT = SQL_TEXT || '  DECLARE LOG_ID INT;' || EOL;
    SQL_TEXT = SQL_TEXT || 'BEGIN' || EOL;

    SQL_TEXT = SQL_TEXT || '  EXECUTE PROCEDURE REPL_WRITE_LOG.BEGIN_OPERATION(' || '''' || ATable || ''', ''U'', ''' || PK_FIELDNAME || ''', OLD.' || PK_FIELDNAME || ') RETURNING_VALUES LOG_ID;' || EOL;
    FOR
      SELECT
           F.FIELD_SOURCE AS FIELD_NAME,
           F.FIELD_TYPE,
           F.FIELD_SCALE,
           F.FIELD_POS
      FROM
          TABLE_MAP T
          JOIN FIELD_MAP F ON F.CODE_TABLE_MAP = T.CODE_TABLE_MAP
      WHERE T.CODE_SENDER = 1 AND T.TABLE_SOURCE = :ATable
      ORDER BY F.FIELD_POS
      AS CURSOR C
    DO
    BEGIN
      SQL_TEXT = SQL_TEXT || '  IF (NEW.' || C.FIELD_NAME || ' IS DISTINCT FROM OLD.' || C.FIELD_NAME || ') THEN' || EOL;
      SQL_TEXT = SQL_TEXT || '    EXECUTE PROCEDURE REPL_WRITE_LOG.WRITE_' || C.FIELD_TYPE ||'_VALUE(LOG_ID, ''' || C.FIELD_NAME || ''', NEW.' || C.FIELD_NAME || ');' || EOL;
    END
    SQL_TEXT = SQL_TEXT || 'END' || EOL;
    SUSPEND;
  END
13 сен 19, 10:43    [21970156]     Ответить | Цитировать Сообщить модератору
 Re: Логирование изменений  [new]
romero111
Member

Откуда:
Сообщений: 6
KreatorXXI, выполняется, но не хочет понимать old.tag_id, например. Сейчас :field_name = tag_id.

:field_value = 'old.' || lower(:field_name);

execute statement 'insert into LOG_FIELDS (LOG_TABLE_ID,FIELD_NAME, FIELD_TYPE, INT_VALUE) values (' || :sequence_id || ',''' || :field_name || ''',''' || :type_data || ''',' || :field_value || ')'
on external :setting_value
as user :user_login password :user_pass;

Пишет, что не знает такое поле....
13 сен 19, 10:57    [21970171]     Ответить | Цитировать Сообщить модератору
 Re: Логирование изменений  [new]
romero111
Member

Откуда:
Сообщений: 6
Симонов Денис,

красиво. Спасибо, что поделились творчеством. Полезная идея.
13 сен 19, 10:58    [21970173]     Ответить | Цитировать Сообщить модератору
 Re: Логирование изменений  [new]
kdv
Member

Откуда: iBase.ru
Сообщений: 28117
romero111,

оператор, выполняемый execute statement не имеет доступа к "внешнему" контексту. Допустим, когда оно вызывается из триггера, оператор ES ни про какой триггер понятия не имеет. Он выполняется точно так же, как любой клиентский запрос.
13 сен 19, 13:16    [21970281]     Ответить | Цитировать Сообщить модератору
Все форумы / Firebird, InterBase Ответить