Программирование >>  Oracle 

1 ... 297 298 299 [ 300 ] 301 302 303 ... 469


1314

Глава 18

Последнее действие в функции init - вызов функции OCIFileInit. Она инициализирует набор функций OCI для работы с файлами, чтобы можно было открывать файлы операционной системы для чтения/записи. Можно было бы использовать и стандартные функции fopen, fclose, iread и iwrite языка С. Использованный подход позволяет сделать внешнюю процедуру более переносимой и обеспечить единообразную обработку ошибок на различных платформах. В функцию init можно добавить и другие вгзовы. Например, если предполагается использование функций OCIFormat* (аналогичнгх функции vsprintf языка С), можно добавить в функцию инициализации вызов OCIFormatInit. He забудьте при этом добавить соответствующий вызов OCIFormatTerm в представленную ниже функцию term.

if (OCIFileInit(myCtx->envhp, myCtx->errhp) ! = OCI SUCCESS) {

raise application error(myCtx, 20000, %s , lastOciError(myCtx));

return NULL;

return myCtx;

Теперь перейдем к упомянутой функции term. Это функция завершения и очистки; ее нужно вызывать после каждого успешного вызова функции init. Это должна быть последняя функция, вызываемая перед возвратом управления из внешней процедуры на языке С в SQL:

static void term(myCtxStruct * myCtx)

OCIFileTerm(myCtx->envhp, myCtx->errhp);

Создание шаблона закончено. Я использую один и тот же шаблон исходного кода для всех своих проектов по созданию внешних процедур (с небольшими изменениями, если используется только библиотека OCI, а не сочетание Pro*С и вызовов OCI). Такой шаблон экономит большое количество времени и обеспечивает множество функциональных возможностей.

Теперь начнем добавлять специфический код. Сразу же после общих компонентов я перечисляю все коды ошибок, которые будет возвращать функция, начиная с 20001. Перечислив их в самом начале, можно задать соответствующие исключительные ситуации с помощью конструкций pragma exception init в коде на языке PL/SQL. Это позволит перехватывать в программах на PL/SQL исключительные ситуации с определенными именами, а не проверять коды ошибок. Я не буду демонстрировать это в данном примере, но в следующем примере с использованием прекомпилятора Рго*С - продемонстрирую. Коды ошибок должны быть в диапазоне от 20000 до 20999, поскольку именно эти коды ошибок выделяются сервером Oracle для приложений; остальные коды ошибок ИСПОЛЬЗУЮТСЯ самим сервером.

#define ERROR OCI SRROR 20001 #define ERROR STR TOO SMALL 2 0002 #define ERROR RAW TOO SMALL 20003 #define ERROR CLOB NULL 2 0004 #define ERROR ARRAY NULL 20005



Внешние процедуры на языке С

1315

Переходим к первой специфической функции. Это реализация процедуры pass number, заданной в представленном ранее PL/SQL-пакете. Она принимает из PL/SQL параметр типа NUMBER в режиме IN и устанавливает параметр типа NUMBER, переданный в рсиме OUT. Функция выполняет следующие действия.

Использует внутренний тип данных Oracle OCINumber с помощью соответствующих функций. В данном случае тип данных Oracle NUMBER преобразуется в тип данных double языка С с помощью встроенной функции OCINumberToReal. Можно преобразовать данные типа NUMBER в строку с помощью функции OCINumberToText или в тип данных int языка С с помощью функции OCINumberToInt. В библиотеке OCI имеется почти SO числовых функций для выполнения различных операций с внутренним типом данных. Описание всех имеющихся функций можно найти в руководстве Oracle Call Interface Programmers Guide.

Обрабатывает данные типа double. В данном случае мы просто меняем знак числа: если число было положительным, мы делаем его отрицательным, и наоборот.

Устанавливает параметру типа NUMBER, переданному в режиме OUT, полученное значение с измененным знаком, и завершает работу.

Перед каждой функцией, вызываемой из языка PL/SQL, указывается макрос, обеспечивающий ее переносимость. Этот макрос экспортирует функцию. Это необходимо только на платформе Windows, а в ОС UNIX - нет. Я обычно включаю этот макрос независимо от платформы, для которой создается внешняя процедура, поскольку мне часто приходится переносить библиотеки внешних процедур из Windows в UNIX, и наоборот. Постоянное включение макроса упрощает перенос. Встроенные в код комментарии объясняют его назначение по ходу дела:

#ifdef WIN NT declspec(dllexport) #endif

void pass number (OCIExtProcContext

* ctx

p inum p inum i

p onum p onum i

/* контекст */, /* OCINumber */,

/* INDICATOR short

/* OCINumber */,

/* INDICATOR short

OCINumber * short

OCINumber * short *

double l inum; myCtxStruct*myCtx;

До выполнения люб1х действий необходимо получить контекст сеанса. При этом будет получена среда OCI, значения параметров и т.д. Этот вызов будет выполняться первым во всех внешних процедурах:

if ((myCtx = init( ctx )) = NULL) return; debugf(myCtx, Вход в функцию Pass Number ) ;

Обратимся к первому параметру. Мы передали его как данные типа OCINumber. Теперь к нему можно применять множество функций OCINumber*. В данном случае



1316

Глава 18

данные типа NUMBER преобразуются в данные типа double языка С с помощью функции OCINumberToReal. Так же просто преобразовать их в данные типа int, long, float

или в форматированную строку.

Сначала необходимо убедиться, что передано не пустое значение типа NUMBER; если - да, оно обрабатывается, если же - нет, вызывается функция term(). Если удалось успешно получить первый параметр, мы изменяем его знак, после чего создаем на основе полученного значения данные типа OCINumber с помощью функции OCINumberFromReal. Если это получилось, устанавливаем в индикаторе пустого значения p onum I признак NOTNULL, чтобы в вызывающей среде можно было понять, что возвращается непустое значение. Обработка закончена. Вызываем функцию term для освобождения ресурсов и возвращаем управление:

if (p inum i = OCI IND NOTNULL) {

if (OCINumberToReal(myCtx->errhp, p inum, sizeof(l inum) , &l inum) !=OCI SUCCESS)

raise application error(myCtx,ERROR OCI ERROR,

%S ,lastOciError(myCtx));

else {

debugf(myCtx, Первый параметр: %g , l inum); l inum = -l inum;

if(OCINumberFromReal(myCtx->errhp, &l inum,

sizeof(l inum) , p onum) ! = OCI SUCCESS)

raise application error(myCtx,ERROR OCI ERROR,

%s ,lastOciError(myCtx));

else

*p onum i = OCI IND NOTNULL; debugf(myCtx,

Устанавливаем параметр OUT равным %g, а ндаторную ->переменную- равной NOTNULL ,

l inum);

term(myCtx) ;

Вот и все. Наша первая внешняя процедура использует все вспомогательные функции: raiseapplicationerror, lastOciError, init, term и debugf. При тестировании этой процедуры мы проверим результаты вызова функции debugf. Они подтвердят, что функция делает именно то, что и предполагалось (представляя собой удобное средство для отладки).



1 ... 297 298 299 [ 300 ] 301 302 303 ... 469

© 2006 - 2025 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки.
Яндекс.Метрика