|
Программирование >> Oracle
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. Они подтвердят, что функция делает именно то, что и предполагалось (представляя собой удобное средство для отладки).
|
© 2006 - 2025 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |