Выбрать главу

Различные реализации доступа к данным часто объединяют пересылку на сервер единичного изменения, добавления или удаления с немедленным COMMIT RETAIN В механизм, дублирующий "автоподтверждение". Общим для уровней интерфейса является реализация возможности автоподтверждения для "молчаливого" управления транзакцией, запуская транзакцию невидимо для программиста в ситуациях, когда написанный программистом код пытается передавать оператор без предварительного старта транзакции.

Явное управление транзакциями стоит дополнительных усилий, особенно если вы применяете продукт, использующий такие гибкие средства, которые предоставляет Firebird. В загруженном работой окружении вариант COMMIT RETAIN может сократить время выполнения и ресурсы, однако он имеет некоторые серьезные недостатки.

* Транзакция SNAPSHOT продолжает хранить первоначальный образ базы данных, что означает, что пользователь не видит подтвержденных результатов других транзакций, которые ожидали подтверждения при старте текущей транзакции.

* Пока та же транзакция продолжает выполнять подтверждение в варианте RETAIN, ресурсы, используемые на сервере, не освобождаются, что приводит к чрезмерному росту ресурсов памяти, потребляемых TSB. Этот рост сильно ухудшает производительность, в конечном счете "замораживая" сервер, и при неблагоприятных условиях операционной системы даже может привести к краху системы.

* Никакие старые версии записей, ставшие устаревшими в результате операций, подтвержденных в транзакциях COMMIT RETAIN, не могут быть включены в сборку мусора, т. к. исходная транзакция никогда не выполняет "жесткого подтверждения".

Оператор ROLLBACK

Как и COMMIT, оператор ROLLBACK освобождает ресурсы на сервере и завершает физический контекст транзакции. При этом вид состояния базы данных в приложении возвращается к тому виду, как если бы эта транзакция никогда не стартовала. В отличие от COMMIT данный оператор никогда не завершается с ошибкой.

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

RollbackRetaining

SQL в Firebird не реализует синтаксис RETAIN В ROLLBACK так же, как это делается в COMMIT. При этом похожий механизм клонирования реализован в функции API isc_roiiback_retaining(). Она восстанавливает для приложения вид базы данных в то состояние, которое было, когда транзакция получила дескриптор или, в случае транзакции READ COMMITTED, в то состояние, которое было при последнем вызове

isc_roiiback_retaining(). Выделенные для транзакции системные ресурсы не освобождаются, курсоры сохраняются.

ROLLBACK RETAIN имеет те же самые ловушки, что и COMMIT RETAIN - и даже больше. Поскольку отдельные вызовы откатов производятся в ответ на исключение некоторого вида, сохранение контекста транзакции также сохранит и причины исключения. ROLLBACK RETAIN не должен использоваться в тех случаях, если существует шанс, что ваш последующий код обработки исключения не найдет и не исправит наследуемое исключение. Любые последующие ошибки ROLLBACK RETAIN должны обрабатываться с полным откатом транзакции для освобождения ресурсов и устранения проблемы.

Диагностирование исключений

Основные причины возникновения ошибок при пересылке данных или подтверждении работы включают:

* конфликты блокировок;

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

* "хорошие данные", которые нарушают ограничение CHECK или другие проверки;

* нарушения первичного или внешнего ключей;

* и другие!

Firebird распознает большое количество различных (более того, поразительных!) исключений и возвращает код ошибки для их идентификации на двух уровнях:

* на высоком уровне существует переменная SQLCODE, определенная (более или менее, с ударением на "менее") в стандарте SQL;

* на более детальном уровне присутствует GDSCODE - индикатор большего размера, более точно определяющий тип исключений, которые сгруппированы на предыдущем уровне в типе SQLCODE.

SQLCODE

В табл. 27.2 представлены значения стандартов SQL-89 и SQL-92, определенные для SQLCODE.

Таблица 27.2. Значения SQLCODE

SQLCODE

Сообщение

Интерпретация

0

SUCCESS

Операция завершилась успешно

1-99

SQLWARNING

Предупреждающее или информационное сообщение сервера

100

NOT FOUND

Была запрошена операция, для которой не было найдено строк. Это не ошибка - код часто просто сообщает о том, что определено условие "конец файла" или "конец курсора" или что не найдено соответствующих значений

<0

SQLERROR

Указывает, что оператор SQL не был завершен. Числа находятся в диапазоне от -1 до -999

Описание отрицательных значений SQLCODE для конкретных ошибок не содержится в стандартах. Отрицательные значения SQLCODE в Firebird являются довольно обобщенными, они представлены группами, которые в значительной степени получены случайно и очень часто своим составом изумляют. Например, можно установить, что значение SQLCODE -204 означает "нечто неизвестное", однако сам код ничего не говорит, что именно неизвестно.

GDSCODE

Второй уровень, GDSCODE, предоставляет гораздо больше возможностей определения исключений. Каждый код GDSCODE является знаковым целым, константы которого представлены в iberror.h (или в interbase.msg, если вы используете версию 1.0.x)[105]. Как правило, сообщение GDSCODE достаточно точно указывает, что произошло[106]. В Firebird 1.5 значительно улучшена информация, передаваемая в сообщениях. Тем не менее GDSCODE предоставляет для приложений наиболее полезный механизм диагностики; вы можете преобразовать константы в пользовательские сообщения в вашем модуле на включающем языке для использования в обработчиках исключений.

Получение исключений

В следующем примере приложение делает попытку добавить данные в таблицу, которая не существует:

INSERT INTO NON_EXISTENT (TEST)

VALUES ('ABCDEF');

Следующая информация об ошибке возвращается приложению (утилита администратора IB SQL в этом случае):

ISC ERROR CODE:335544569 <- GDSCODE

Dynamic SQL Error <- corresponding text from firebird.msg

SQL error code = -204 <- SQLCODE

Table unknown <- corresponding text from firebird,msg

NON_EXI STENT

Откуда приложение получает коды ошибок и сообщения? Ответ можно найти в векторе состояния ошибки (error status vector), в массиве, который передается в качестве параметра в большинство функций API. Эти функции возвращают состояние и коды ошибок клиенту вместе с соответствующими строками из файла сообщений Firebird[107]. API также предоставляет клиентским приложениям служебные функции для чтения содержимого векторов состояния ошибок в локальных буферах. Обработчики ошибок могут затем анализировать содержимое этих буферов и использовать полученную информацию для принятия решения, как поступить с исключением, а также выдать пользователю дружественное сообщение.

iberror.h

Заголовочный файл iberror.h в вашем каталоге /include содержит объявления, каждое из которых связано с SQLCODE и GDSCODE через символическую константу. Например, вот объявления констант для двух кодов ошибок из предыдущего примера:

вернуться

105

Неанглийские версии файла сообщений не были доступны во время написания данной книги. Готовятся проекты трансляции. Если вас интересует локализованный файл сообщений, обратитесь к спискам сообщества Firebird. Сообщите, что вы заинтересованы в участии в проектах локализации!

вернуться

106

Существует несколько неприятных исключений из этого правила. Например, ISC ERROR CODE: 335544321 "Arithmetic exception, numeric overflow, or string truncation" (Арифметическое исключение, числовое переполнение или усечение строки) объединяет такой широкий диапазон возможностей, что оно обычно вызывает состояние изумления даже у программиста, который допустил возможность появления такого исключения.

вернуться

107

Если клиентская библиотека удаленного клиента находит локальную копию файла сообщений в известном "корневом" каталоге, Firebird 1.5 будет использовать именно ее и перекроет этот файл в каталоге сервера RootDirectory. Поскольку до сих пор не решено, является ли это желательной возможностью, то может быть разумным устранить зависимость от такого поведения в интересах будущей защиты. В любом случае файловые системы рабочих станций являются весьма уязвимыми при неправильном поведении пользователя.