Особенности обработки ошибок сервера базы данных Oracle

К.п.н. Владимир Лихачёв, Калужский педагогический университет им К.Э.Циолковского. Для программ, работающих с базами данных, важным является не только корректность обработки их ошибок, но и формирование информативных сообщений об этих ошибках. Наличие таких сообщений позволяет быстрее выявлять причины и исправлять ошибки. Особенно это актуально при работе с программой конечного пользователя, так как ему в большинстве случаев не известна не только структура конкретной БД, но и теоретические основы реляционных баз данных. Как ни странно, ситуация с формированием сообщений об ошибках в программах довольно часто сильно отличается от обработки самих ошибок. При обработке ошибок обычно удается выработать общую стратегию, что позволяет локализовать их обработку в одной или нескольких функциях. Аналогичный подход для сообщений об ошибках может быть реализован на основе того, что в сообщении об ошибке сервер Oracle указывает тип ошибки и объект базы данных, который явился причиной её возникновения. Такими объектами обычно являются ограничения, как, например, первичные, уникальные и внешние ключи, уникальные индексы, ограничения “not null” и др. Из системных таблиц и представлений базы данных может быть получена подробная информация об этих ограничениях и определены значения, изменение которых и привело к возникновению ошибки. Но проблема заключается в том, что реализация такого механизма формирования сообщений об ошибках в реальных приложениях встречает целый ряд сложностей: Зависимость сообщения об ошибке от назначения программы. Даже для программ, работающих с одной и той же базой данных, может потребоваться формирование различных сообщений об одной и той же ошибке. Например, в программе для редактирования данных пользователем сообщение должно быть: “Товар с таким названием уже зарегистрирован! Проверьте название товара!”. А в программе импорта данных требуется сообщение с совершенно другим содержанием: “Импортируемые данные дублируются – проверьте дату, за которую выполняется импорт данных!”. Сложность формирования сообщений для некоторых ошибок, вызванных ограничениями базы данных. Например, в ограничениях CHECK для таблиц могут использоваться довольно сложные запросы и условия. Поэтому формирование сообщений на основе их анализа может оказаться довольно сложной задачей. Использование в клиентских программах пользовательских названий таблиц и столбцов, отличных от их имен в БД. Например, таблица имеет имя “GOODS”, а в клиентском приложении данные этой таблицы могут отображаться в справочнике как “Товары” или “Продукция”. Совокупность этих факторов обычно приводит к тому, что формирование сообщений даже об однотипных ошибках реализуется индивидуально для каждой транзакции. В результате код для формирования сообщений об ошибках оказывается распределенным по всему приложению, что усложняет его сопровождение. Из-за необходимости написания кода практически для каждой возможной ошибки, часть ошибок, о которых известно разработчику, оказываются без соответствующих сообщений для пользователя. В результате достаточно информативные сообщения для конечного пользователя формируются только для некоторой части ошибок, в остальных же случаях ему остается довольствоваться в лучшем случае сообщениями от самого сервера базы данных. Информативность таких сообщений для обычного пользователя в большинстве случаев недостаточна для выявления причины возникшей проблемы и её устранения. Рассматриваемый в статье метод формирования информативных сообщений об ошибках для пользователя является довольно универсальным, может быть реализован как в клиентских приложениях, так и на стороне сервера Oracle. Он может использоваться в различных типах программ, как, например: Программы, использующие специальный интерфейс для ввода и изменения данных БД. В большинстве случаев информативные сообщения об ошибках могут быть получены на основе анализа структуры базы данных. Это позволит информировать пользователя об их причине с минимальными затратами усилий со стороны разработчиков и программного обеспечения. Программы с возможностью построения пользователем произвольных SQL-запросов. Формирование сообщений на основе анализа структуры базы данных может быть особенно актуально для программ, которые ориентированы на широкий круг пользователей, в том числе и с низким уровнем знаний в этой области. Это позволит сделать более понятными для пользователя сообщения об ошибках в SQL-запросах. Предметные платформы. Использование методов, описанных в статье, позволит самой предметной платформе формировать информативные сообщения об ошибках базы данных на основе анализа её структуры. Это даст возможность сократить код на языке платформы, используемый для обработки ошибочных ситуаций. А ошибки, которые требуют специальных сообщений, но оказались без таковых, будут достаточно информативными для того, чтобы намного упростить выявление их причины. Описанные выше проблемы формирования сообщений могут быть решены, если сообщения об ошибках условно разделить на две группы: универсальные сообщения, которые формируются на основе анализа структуры базы данных; специальные сообщения, которые определяются индивидуально для каждой ошибки. Описываемый в статье метод формирования сообщений об ошибках БД может быть применён для многих серверов реляционных баз данных. Пример его использования для баз данных сервера Firebird рассматривается в статье [1]. Если клиентское приложение разработано на Object Pascal (Delphi, Kylix, Free Pascal), то для выявления причин непредвиденных ошибок могут быть полезны возможности библиотеки JEDI [2]. 1. Универсальные сообщения об ошибках, вызванных ограничениями БД Как уже говорилось выше, основная идея создания универсальных сообщений заключается в том, чтобы на основе данных из сообщения об ошибке от Oracle и о структуре базы данных сформировать достаточно информативное и понятное для конечного пользователя сообщение. Предположим, в таблицу “GOODS” (скрипт 1.1) пользователь пытается добавить товар с названием (столбец “TITLE”), которое уже имеется в таблице. CREATE TABLE DEMO.GOODS ( CODE INTEGER NOT NULL , TITLE VARCHAR2(50 byte) NOT NULL , PRICE NUMBER(16, 2) NOT NULL , CONSTRAINT CK_PRICE CHECK (PRICE > 0), CONSTRAINT PK_GOODS PRIMARY KEY(CODE)); COMMENT ON TABLE DEMO.GOODS is 'Товары'; COMMENT ON COLUMN DEMO.GOODS.CODE is 'Код товара'; COMMENT ON COLUMN DEMO.GOODS.TITLE is 'Название'; COMMENT ON COLUMN DEMO.GOODS.PRICE is 'Цена'; CREATE UNIQUE INDEX DEMO.IDX_GOODS_TITLE ON DEMO.GOODS (TITLE); Скрипт 1.1. Создание таблицы “GOODS”. Сервер в этом случае сгенерирует ошибку, так как столбец “TITLE”, в котором хранится название товара, включено в уникальный индекс “DEMO.IDX_GOODS_TITLE”: ORA-00001: нарушено ограничение уникальности (DEMO.IDX_GOODS_TITLE) Вместо этого сообщения для пользователя может быть сформировано, например, одно из сообщений: Значение поля “Название” в таблице “Товары” должно быть уникальным! Товар с таким названием уже зарегистрирован! Проверьте название товара! В справочнике товаров не могут быть товары с одинаковыми названиями! Хотя эти сообщения и различаются, но в них всех указывается информация об объекте, для которого нарушено ограничение уникальности – это поле “Название” таблицы “Товары”. Одна из проблем формирования такого типа сообщений, заключается в том, что пользовательские названия полей и таблиц, отличаются от имен таблиц и столбцов в базе данных. Чтобы пользователю было понятно сообщение об ошибке, в нем должны использоваться именно пользовательские названия. Для сопоставления имен таблиц и полей и их пользовательских названий может использоваться отдельная таблица или комментарии для таблиц и столбцов. Последний вариант можно считать более предпочтительным, так как это позволяет одновременно документировать базу данных. Именно поэтому в скрипте 1.1 в качестве комментариев для таблицы и её столбцов приведены их пользовательские названия. Если сравнить выше приведённые сообщения и комментарии для таблицы и столбцов, то можно заметить, что формирование первого сообщения является наиболее простым вариантом. Для формирования двух других сообщений может потребоваться лексический синтез, но это уже отдельная задача. Хочется обратить внимание, что в дальнейшем в статье приводится только один из возможных вариантов сообщения для каждого случая ошибки. На практике выбор стиля сообщения и его содержания может зависеть от целого ряда факторов и будет определяться разработчиком системы. Конечно, нельзя исключать ситуацию, когда для таблицы или столбца отсутствуют комментарии, которые должны быть указаны в сообщении. В этой ситуации в сообщении об ошибке возможно отображение непосредственно имени таблицы или столбца. Далее рассматривается формирование универсальных сообщений для наиболее часто встречающихся ошибок, обусловленных ограничениями БД. 2. Не указано значение поля, обязательного для заполнения (ограничение NOT NULL) нарушено ограничение “not null”, установленное для столбца; не указано значение столбца, входящего в уникальный индекс, главный или уникальный ключи. ORA-01400: невозможно <вставить/заменить> NULL в ("<Схема>"."<Таблица>"."<Столбец>") Для получения описания таблицы и столбца из сообщения об ошибке, можно использовать запрос 2.1. select tc.comments astable_comment, cc.comments ascolumn_comment from all_tab_columns c, all_tab_comments tc, all_col_comments cc where c.owner = :owner and c.table_name = :table_name and c.column_name = :column_name and tc.owner = c.owner and tc.table_name = c.table_name and cc.owner = c.owner and cc.table_name = c.table_name and cc.column_name = c.column_name Запрос 2.1. Получение описания таблицы и столбца В качестве параметров запроса “owner”, ”table_name”, ”column_name” необходимо указать соответственно имя схемы, таблицы и столбца из сообщения об ошибке. Запрос возвращает комментарии для таблицы и столбца. Используя результаты этого запроса, может быть сформировано сообщение об ошибке, например, следующего содержания: Необходимо указать значение столбца “<Описание поля>” в таблице “<Описание таблицы>” при <добавлении новой/изменении> записи. 3. Нарушена уникальность значения поля или набора столбцов столбец входит в уникальный индекс. ORA-00001: нарушено ограничение уникальности (<Схема>.<Ограничение>) В сообщении об ошибке указывается ограничение, которое вызвало ошибку. Для получения информации о столбцах, входящих в главный или уникальный ключи, можно использовать запрос 3.1, для получения информации об индексе - запрос 3.2. select dcs.constraint_type, cc.table_name, tc.comments astable_comment, cc.column_name, ccom.comments as column_comment from all_cons_columns cc join all_tab_comments tc on (tc.owner = cc.owner and tc.table_name = cc.table_name) join all_col_comments ccom on (ccom.owner = cc.owner and ccom.table_name = cc.table_name and ccom.column_name = cc.column_name ) join all_constraints dcs on (dcs.constraint_name = cc.constraint_name) where cc.owner = :owner and cc.constraint_name = :key_name Запрос 3.1. Получение информации о столбцах таблицы, входящих в главный или уникальный ключи. select ic.table_name, tc.comments astable_comment, ic.column_name, ccom.comments ascolumn_comment from all_ind_columns ic join all_tab_comments tc on (tc.owner = ic.table_owner and tc.table_name = ic.table_name) join all_col_comments ccom on (ccom.owner = ic.table_owner and ccom.table_name = ic.table_name and ccom.column_name = ic.column_name ) where table_owner = :owner and index_name = :index_name Запрос 3.2. Получение информации о столбцах таблицы, входящих в индекс. В качестве параметров запросам передаётся имя схемы (“owner“), имя кл

Hosted by uCoz