|
Кто удалил запись из таблицы?
Если в вашей системе не используется OpenEdge Auditing, а само приложение не создает никаких собственных журналов аудита, как в такой ситуации можно узнать, кто и когда удалил конкретную запись из таблицы? В этом помогут архивы AI-экстентов, конечно же, если в этой базе данных работает механизм After-Imaging. Методика поиска «виноватого» описана далее на примере базы данных sports.
Скопируйте базу sports из каталога $DLC. Включите механизмы After-Imaging и AI File Management. Запустите базу данных. Сформируйте резервную копию базы sports в online и представьте, что это резервная копия промышленной базы, сделанная накануне вечером. Как всё это сделать, здесь я описывать не буду, т.к. об этом много рассказывалось в предыдущих статьях и книгах на этом сайте.
Итак, чтобы найти требуемую информацию необходимо:
-
иметь доступ к архивам AI-экстентов, созданных в промежутке времени, во время которого мы предполагаем, что произошло удаление;
-
знать имя таблицы, из которой была удалена запись;
-
знать имя области хранения, в которой находится таблица;
-
знать RECID удаленной записи или номер блока, в котором она хранилась.
Для начала нужно удалить какую-нибудь запись из базы. В качестве «жертвы» возьмем запись с номером 54 из таблицы Family.
Подключитесь к базе sports в режиме редактора: mpro sports
Выполните следующий ABL-код:
find last family where empnum = 54 exclusive-lock.
delete family.
Отключитесь от базы данных и дождитесь, когда сформируется очередной архив AI-экстента. Время формирования зависит от того, какой интервал архивирования AI-экстентов был выставлен для механизма AI File Management. А пока определим, какой RECID был у этой записи.
Восстановите базу данных sports в отдельный каталог из ранее созданной резервной копии: prorest ./db1/sports ./backup/sports.bkp
Подключитесь к восстановленной базе в режиме редактора и выполните следующий ABL-код:
find last family where empnum = 54 no-lock.
displ recid(family).
Результатом работы этой программы будет значение RECID, выведенное на экран монитора. Оно будет равно 510.
Теперь нужно узнать, в какой области хранения находится эта таблица. Это можно сделать либо с помощью команды PROUTIL TABANALYS, либо с помощью Data Dictionary.
PROUTIL TABANALYS:
Выполните команду: proutil sports –C tabanalys > tabanalys.txt
Откройте созданный файл tabanalys.txt и найдите в нем информацию о таблице Family. Пример для базы sports: RECORD BLOCK SUMMARY FOR AREA "Employee" : 7 -Record Size(B)- --Fragments-- Scatter
Table Records Size Min Max Mean Count Factor Factor
PUB.Benefits 21 848.0B 39 41 40 21 1.0 1.0
PUB.Department 7 211.0B 26 35 30 7 1.0 2.0
PUB.Employee 55 6.2K 99 135 115 55 1.0 1.0
PUB.Family 70 3.0K 38 51 44 70 1.0 1.0
Здесь мы видим, что таблица хранится в области «Employee», которая имеет порядковый номер 7.
Data Dictionary:
Подключитесь к базе данных sports в режиме редактора и перейдите в меню Tools -> Data Dictionary -> Database -> Reports -> Detailed Table. В появившемся диалоговом окне выберите название таблицы Family и нажмите клавишу «Enter». Откроется диалоговое окно «Report Options», которое позволяет настраивать параметры отчета. Ничего не меняйте, нажмите клавишу «F1». На экран будет выведен отчет с информацией по таблице Family. Найдите в отчете строку «Storage Area:», которая и будет указывать на имя области, в которой хранится таблица, в нашем случае это область хранения «Employee».
После того, как найдено имя области хранения, необходимо найти значение RPB для этой области. Воспользуйтесь структурным файлом базы данных (sports.st), предварительно обновив его командой: prostrct list sports
Откройте файл sports.st и найдите в нем описание области «Employee». В ее описании значение RPB равно 32 (выделено жирным шрифтом на следующем примере): d "Employee":7,32;1
Получив значения RECID и RPB необходимо рассчитать значение DBKEY. Для этого разделите RECID на RPB, отбросьте дробную часть, результат умножьте на RPB. Это и будет DBKEY:
510 / 32 = 15,9375
DBKEY = 15 х 32 = 480
Теперь вам известно значение DBKEY, можно приступить к его поиску в сформированных к этому времени архивах AI-экстентов. Для этого перейдите в каталог с архивами AI-экстентов, выделите из них те, которые были сформированы в промежутке времени, охватывающем последний, по вашему мнению, момент существования записи и момент, когда ее уже не стало; или воспользуйтесь всеми архивами. После этого выгрузите AI-заметки из выбранных AI-экстентов в отдельный файл следующей командой: rfutil sports -C aimage scan verbose -a ai-file-name >> scanai.txt
Чтобы не выполнять эту команду вручную для каждого AI-экстента, можно автоматизировать этот процесс с помощью следующей команды: for ai in `ls -1 ./*.sports.a*`; do rfutil sports -C aimage scan verbose -a $ai >> scanai.txt ; done
После этого необходимо в файле scanai.txt найти все данные, связанные с DBKEY и с номером области хранения. В нашем случае ищем 480 (DBKEY) и отсекаем по номеру области 7:
cat scanai.txt | grep 480 | grep 7
Trid: 3942 area = 7 dbkey = 480 update counter = 35 (12529)
Trid: 3942 area = 7 dbkey = 480 update counter = 36 (12529)
Trid: 3942 area = 7 dbkey = 480 update counter = 37 (12529)
Теперь нужно найти все AI-заметки транзакции, в которой выполнялось удаление. В данном случае это «Trid: 3942»: cat scanai.txt | grep "Trid: 3942"
Результат будет выглядеть так: Trid: 3942 Thu May 27 14:42:48 2010. (2598)
Trid: 3942 User Id: val (12531)
Trid: 3942 code = RL_TBGN version = 1 (12528)
Trid: 3942 dbkey = 0 update counter = 0 (12530)
Trid: 3942 code = RL_IXDEL version = 2 (12528)
Trid: 3942 dbkey = 0 update counter = 0 (12530)
Trid: 3942 code = RL_BKREPL version = 1 (12528)
Trid: 3942 area = 7 dbkey = 192 update counter = 209 (12529)
Trid: 3942 code = RL_RMDEL version = 2 (12528)
Trid: 3942 area = 7 dbkey = 480 update counter = 35 (12529)
Trid: 3942 code = RL_RMCR version = 2 (12528)
Trid: 3942 area = 7 dbkey = 480 update counter = 36 (12529)
Trid: 3942 code = RL_BKBBOT version = 1 (12528)
Trid: 3942 area = 7 dbkey = 480 update counter = 37 (12529)
Trid: 3942 code = RL_BKMBOT version = 2 (12528)
Trid: 3942 area = 7 dbkey = 64 update counter = 62 (12529)
Trid: 3942 code = RL_BK2EB version = 2 (12528)
Trid: 3942 area = 7 dbkey = 512 update counter = 38 (12529)
Trid: 3942 Thu May 27 14:42:48 2010. (2598)
Trid: 3942 code = RL_TEND version = 1 (12528)
Trid: 3942 dbkey = 0 update counter = 0 (12530)
Жирным шрифтом выделена интересующая нас информация. Теперь мы знаем, что в четверг 27 мая 2010 года в 14 часов 42 минуты 48 секунд (Thu May 27 14:42:48 2010) запись была удалена пользователем val (User Id: val).
Строка с RL_RMDEL указывает на то, что была выполнена операция удаления, а следующая за ней строка содержит информацию с номером области хранения (area = 7) и с DBKEY (dbkey = 480).
Описанный пример явно демонстрирует, что механизм After-Imaging полезен не только с точки зрения дополнительного резервного копирования базы данных, но и с точки зрения «помощника» при разрешении таких инцидентов, как несанкционированное удаление информации из базы.
|