Особливості обробки помилок сервера бази даних Oracle, Інші СУБД, Бази даних, статті

Для програм, що працюють з базами даних, важливим є не тільки коректність обробки їхніх помилок, а й формування інформативних повідомлень про ці помилки. Наявність таких повідомлень дозволяє швидше виявляти причини і виправляти помилки. Особливо це актуально при роботі з програмою кінцевого користувача, так як йому в більшості випадків не відома не тільки структура конкретної БД, а й теоретичні основи реляційних баз даних.


Як не дивно, ситуація з формуванням повідомлень про помилки в програмах досить часто сильно відрізняється від обробки самих помилок. При обробці помилок зазвичай вдається виробити загальну стратегію, що дозволяє локалізувати їх обробку в одній або декількох функціях. Аналогічний підхід для повідомлень про помилки може бути реалізований на основі того, що в повідомленні про помилку сервер Oracle вказує тип помилки і об’єкт бази даних, який став причиною її виникнення. Такими об’єктами зазвичай є обмеження, як, наприклад, первинні, унікальні і зовнішні ключі, унікальні індекси, обмеження “Not null” та ін З системних таблиць і уявлень бази даних може бути отримана детальна інформація про ці обмеження і визначено значення, зміна яких і привело до виникнення помилки. Але проблема полягає в тому, що реалізація такого механізму формування повідомлень про помилки в реальних додатках зустрічає цілий ряд складнощів:



Сукупність цих факторів звичайно призводить до того, що формування повідомлень навіть про однотипних помилках реалізується індивідуально для кожної транзакції. У результаті код для формування повідомлень про помилки виявляється розподіленим по всьому додатку, що ускладнює його супровід. Через необхідність написання коду практично для кожної можливої ​​помилки, частина помилок, про які відомо розробнику, виявляються без відповідних повідомлень для користувача. В результаті достатньо інформативні повідомлення для кінцевого користувача формуються тільки для деякої частини помилок, в інших же випадках йому залишається задовольнятися в кращому випадку повідомленнями від самого сервера бази даних. Інформативність таких повідомлень для звичайного користувача в більшості випадків недостатня для виявлення причини виниклої проблеми і її усунення.


Розглянутий у статті метод формування інформативних повідомлень про помилки для користувача є досить універсальним, може бути реалізований як в клієнтських додатках, так і на стороні сервера Oracle. Він може використовуватися в різних типах програм, як, наприклад:



Описані вище проблеми формування повідомлень можуть бути вирішені, якщо повідомлення про помилки умовно розділити на дві групи:



Описуваний в статті метод формування повідомлень про помилки БД може бути застосований для багатьох серверів реляційних баз даних. Приклад його використання для баз даних сервера 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)


Ця помилка генерується сервером в кількох випадках:



У всіх цих випадках сервер генерує помилку:





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. Порушена унікальність значення поля або набору стовпців


Необхідність введення унікального значення стовпця може вимагатися в основному в трьох випадках:



У всіх трьох випадках Oracle Database генерує одну і ту ж помилку:
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”), ім’я ключа (“key_name”) або індексу (“index_name”). Запити повертають імена та коментарі для таблиць і стовпців, що входять в обмеження. Запит 3.1 повертає так же тип обмеження (“constraint_type”): “P” – головний ключ, “U” – унікальний ключ. Кількість записів, що повертаються запитами, відповідає кількості стовпців в обмеженні унікальності.


На основі отриманої інформації про обмеження унікальності для користувача можуть бути сформовані варіанти повідомлень про помилку, наприклад, наведені в розділі 1.


4. Помилки, викликані обмеженнями зовнішніх ключів


При виконанні операцій над табличними даними, пов’язаними зовнішніми ключами, можна виділити кілька причин, що призводять до виникнення помилок:


1. В підпорядковану таблицю додається запис, в якому для стовпця, що входить у зовнішній ключ, немає відповідного значення в головній таблиці. Аналогічна ситуація відбувається при зміні значення стовпця підпорядкованої таблиці у випадку, якщо нового значення стовпця немає в головній таблиці. Oracle Database в цьому випадку генерує помилку:







  1. ORA-02291: порушено обмеження цілісності (<Схема>. <Зовнішній ключ>) – вихідний ключ не знайдений
    У головній таблиці виконується спроба зміни значення стовпця, на яке є посилання в підпорядкованої таблиці. Для цього випадку Oracle Database генерує помилку:






  1. ORA-02292: порушено обмеження цілісності (<Схема>. <Зовнішній ключ>) – виявлена ​​породжена запис
    У головній таблиці виконується спроба видалення даних, на які є посилання в підпорядкованої таблиці. Якщо у визначенні зв’язку між таблицями вказано обмеження “NO ACTION” для операції видалення даних, то Oracle не дозволяє видаляти дані з головної таблиці, якщо в підпорядкованої таблиці є записи пов’язані з видаляється записом. Для цієї ситуації Oracle Database генерує помилку, аналогічну попереднього випадку.

Для отримання інформації про стовпцях головною і підлеглою таблиць, що входять у зовнішній ключ, можна використовувати наведений нижче запит 4.1.





select    a.constraint_name,
a.table_name,
tc1.comments astable_comment,
a2.column_name,
cc1.comments ascolumn_comment,
b.owner asr_owner,
b.table_name asr_table_name,
tc2.comments asr_table_comment,
b2.column_name asr_column_name,
cc2.comments asr_column_comment
from all_constraints a,
all_constraints b,
all_cons_columns a2,
all_cons_columns b2,
all_tab_comments tc1,
all_col_comments cc1,
all_tab_comments tc2,
all_col_comments cc2
where a.owner = :owner
and a.constraint_type = “R”
and a.constraint_name = :foreign_key
and b.constraint_type in (“P”,”U”)
and b.constraint_name = a.r_constraint_name
and b.owner = a.r_owner
and a2.constraint_name = a.constraint_name
and a2.table_name = a.table_name
and a2.owner = a.owner
and b2.constraint_name = b.constraint_name
and b2.table_name = b.table_name
and b2.owner = b.owner
and b2.position = a2.position
and tc1.owner = a.owner
and tc1.table_name = a.table_name
and cc1.owner = a2.owner
and cc1.table_name = a2.table_name
and cc1.column_name = a2.column_name
and tc2.owner = b.owner
and tc2.table_name = b.table_name
and cc2.owner = b2.owner
and cc2.table_name = b2.table_name
and cc2.column_name = b2.column_name
Запит 4.1. Отримання інформації про зовнішній ключі.

Запит має два параметри: “owner” і “foreign_key” – схема і зовнішній ключ, про який необхідно отримати інформацію. Він повертає інформацію про стовпцях, що входять у зовнішній ключ: “table_name”, “table_comment” – Ім’я та опис підпорядкованої таблиці; “column_name”, “column_comment” – ім’я і опис стовпця підпорядкованої таблиці. Стовпці запиту з префіксом “r_” повертають інформацію про головну таблиці. Кількість записів повертаються запитом відповідає кількості стовпців, що входять у зовнішній ключ.


На основі цієї інформації можуть бути сформовані повідомлення про помилки зовнішніх ключів для користувача.


5. Спеціальні повідомлення про помилки, викликаних обмеженнями БД


Необхідність використання спеціальних повідомлень може виникнути у випадку, якщо універсальне повідомлення про помилку з якихось причин не може використовуватися або не може бути сформовано. Прикладом останнього випадку є обмеження CHECK для таблиць. В умовах обмежень можуть використовуватися запити й умови, аналіз яких може виявитися досить складним завданням. Тому для цих обмежень часто зручніше використовувати повідомлення, які визначаються на етапі розробки.


Можна виділити дві групи спеціальних повідомлень про помилки. Перший тип спеціальних повідомлень призначений для використання у всіх додатках, які працюють c загальною базою даних. Їх можна умовно назвати “Спеціальні повідомлення про помилки рівня бази даних”. Друга група повідомлень специфічна для конкретного додатка. Вони можуть бути необхідні, коли різні додатки повинні видавати користувачу різні повідомлення про одну й ту ж помилку. Їх можна умовно назвати “спеціальні повідомлення про помилки рівня програми”. Інформацію про першої групи повідомлень зручно зберігати в самій базі даних і використовувати для цього окрему таблицю. Повідомлення, специфічні для програми можуть зберігатися в її ресурсах, наприклад, у вигляді окремого файлу або також в БД. Ідентифікація спеціальних повідомлення може на основі коду помилки, імені схеми і одного або декількох ключових слів з повідомлення про помилку.


6. Повідомлення про помилки обмежень CHECK для таблиць


При виникненні помилки, викликаної обмеженням CHECK для таблиці, сервер генерує помилку:
ORA-02290: порушено обмеження цілісності CHECK (<Схема>. <Ім'я обмеження>)


Як вже говорилося вище, для таких помилок часто зручно використовувати спеціальні повідомлення. Наприклад, для обмеження “CK_PRICE” таблиці “GOODS” може використовуватися спеціальне повідомлення, збережене в таблиці спеціальних повідомлень:






Ціна товару в довіднику “Товари” має бути більше нуля.


7.    Комплексне використання спеціальних і універсальних повідомлень про помилки


Гнучкий механізм формування інформативних повідомлень про помилки для користувача реалізується в кілька етапів (рис. 1):


1. Висновок спеціального повідомлення про помилку рівня програми. Спочатку програма виконує пошук повідомлення про помилку серед спеціальних повідомлень для цього додатка. Якщо таке повідомлення знайдено, воно виводиться, і формування повідомлення на цьому завершується.


2. Висновок спеціального повідомлення про помилку рівня бази даних. Якщо на етапі 1 повідомлення не було знайдено, виконується пошук спеціального повідомлення про помилку рівня бази даних. Якщо знайдено, то воно виводиться користувачеві і формування повідомлення про помилку на цьому закінчується.


3. Висновок повідомлення на основі аналізу структури бази даних (універсального повідомлення). У випадку, якщо на попередніх етапах спеціальних повідомлень не виявлено, то воно формується на основі аналізу структури бази даних. Воно виводиться користувачеві і на цьому формування повідомлення завершується.


4. Висновок повідомлення від сервера бази даних. У випадку, якщо на трьох попередніх етапах повідомлення для користувача не було сформовано, то з’являється повідомлення про помилку від Oracle. Така ситуація може виникнути з кількох причин. Наприклад, при виникненні користувальницької помилки, яка була навмисно згенерована в збереженій процедурі або тригері c допомогою функції RAISE_APPLICATION_ERROR, і зміна змісту повідомлення про яку не потрібно.


Можливі більш складні випадки, ніж наведений у цій статті. Наприклад, якщо повідомлення формується в збереженій процедурі, яка в свою чергу може викликатися з тригера або іншої процедури. У цьому випадку може знадобитися також інформація, про те як викликалася процедура, яка формує повідомлення про помилку. І тому вихідне повідомлення може бути доповнена або змінена, наприклад, на основі інформації про стеку виклику збережених процедур і тригерів.


У ряді випадків вони можуть бути навіть більш інформативними, ніж сформовані на попередніх етапах. Наприклад, замість обмеження CK_PRICE для таблиці DEMO.GOODS (скрипт 1.1) можна в тригері перед вставкою і оновленням записи виконувати необхідну перевірку і генерувати повідомлення для користувача в уже “готовому” вигляді:





CREATE OR REPLACE TRIGGER DEMO.TRIGGER_GOODS BEFORE
INSERT
OR UPDATE OF PRICE ON DEMO.GOODS FOR EACH ROW BEGIN
IF :NEW.PRICE <= 0 THEN RAISE_APPLICATION_ERROR (-20001, “Ціна товару” “/ /: NEW.TITLE / /” “Повинна бути більше 0 руб (вказана ціна” / /: NEW.PRICE / / “руб)”);
END IF;
END TRIGGER_GOODS;

У випадку ціни товару меншою або рівною нулю сервер згенерує помилку, наприклад:





ORA-20001: Ціна товару “Лейка” повинна бути більше 0 руб (вказана ціна 0 руб)

Клієнтський додаток може відразу передати це повідомлення користувачеві без зміни.


Іншою причиною може бути поява помилки, для якої формування повідомлення не передбачено.


Рис. 1. Послідовність формування повідомлення про помилку бази даних.


 


Хочеться звернути увагу, що навіть якщо в додатку використовуються тільки спеціальні повідомлення про помилки, то використання загальної функції для формування повідомлень дозволить поліпшити структуру програми. При необхідності формат спеціальних повідомлень може мати підтримку посилань на довідкову систему, малюнки і т.д. Описуваний метод формування повідомлень про помилки бази даних орієнтований більшою мірою на реалізацію в клієнтському додатку. У той же час він може використовуватися на стороні сервера в збережених процедурах, тригерах таблиць, а так само в системних тригерах для події SERVERERROR бази даних або схеми.


Висновок


Метою даної статті є показати основні ідеї методу, який може використовуватися для формування інформативних повідомлень про помилки бази даних Oracle для кінцевого користувача. Хоча за рамками статті залишилися деякі моменти реалізації, хочеться сподіватися, що описаний у статті підхід дозволить зменшити трудовитрати при розробці програмного забезпечення, підвищити його надійність і якість.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*