|
Программирование >> Oracle
1308 Глава 18 typedef struct myCtx OCIExtProcContext * ctx; /* Контекст, передаваем1й внешний /* оцедурам */ OCIEnv * envhp; /* Дескриптор среды OCI */ OCISvcCtx * svchp; /* Дескриптор службы OCI */ OCIError * errhp; /* Дескриптор ошибки OCI */ int curr lineno; char * curr filename; ub1 debugf flag; char debugf path[2 55]; char debugf filename[50]; /* добавьте сюда необходим1е переменные состояния....*/ myCtxStruct; Затем в шаблоне исходного кода следует функция debugf - процедура трассировки. Это С-функция, работающая аналогично стандартной функции fprintf и даже принимающая любое количество аргументов (обратите внимание на троеточие в списке аргументов). Первый ее аргумент - контекст - описанная выше структура, предоставляющая информацию о состоянии. Я всегда предполагаю, что указатель на состояние имеет имя myCtx (в макросе для функции debugf это предположение используется). Функция bu демонстрирует кое-что новое. В ней представлена большая часть функций библиотеки OCI для работы с файлами, которые очень похожи на семейство функций fopenead/ fWrite/fclose языка С. Код функции debugf, который вызывается, только если установлен флаг myCtx->debugf flag, открывает файл, формирует сообщение, записывает его и закрывает файл. Этот код может служить примером того, как используется контекст. Контекст содержит информацию о состоянии сеанса и важные переменные, например структуры OCIEnv и OCIError, необходимые для всех вызовов функций OCI. Показано, как изменять состояние, манипулируя переменными в структуре контекста (как это делает макрос debugf). Макрос debugf позволяет проигнорировать обращения к реализующей трассировку функции debugf(). Дело в том, что если либо контекст myCtx, либо флаг myCtx->debugf flag не установлены, состояние контекста никогда не изменяется, и функция debugf() никогда не вызывается. Это означает, что можно оставить отладочные операторы в производственном коде, поскольку их наличие не повлияет на производительность в долгосрочной перспективе (пока флаг debugf flag имеет значение false). void debugf(myCtxStruct * myCtx, char * fmt, ...) va list ap; OCIFileObject * fp; time t theTime = time(NULL); char msg[8192]; ub4 bytes; if (OCIFileOpen(myCtx->envhp, myCtx->errhp, &fp, myCtx->debugf filenaroe, myCtx->debugf path, Внешние процедуры на языке С 1309 OCI FILE WRITE ONLY, OCI FILE APPENDOCI FILE CREATE, OCI FILE TEXT) != OCI SUCCESS) return; strftime(msg, sizeof(msg), %y%m%d %H%M%S GMT , gmtime(&theTime)); OCIFileWrite(myCtx->envhp, myCtx->errhp, fp, msg, strlen(msg), &bytes); va start(ap,fmt); vsprintf(msg, fmt, ap) ; va end(ap); strcat(msg, \n ); CCIFileWrite(myCtx->envhp, myCtx->errhp, fp, msg, strlen(msg), (bytes); OCIFileClose(myCtx->envhp, myCtx->errhp, fp); Следующий фрагмент кода представляет интерфейсный макрос для функции debugf. Этот макрос использовать удобнее, чем функцию debugf. Вместо обязательной передачи значений LINE , FILE при каждом вызове, достаточно написать: debugf( myCtx, This is some format %s , some string ); и этот макрос автоматически установит соответствующие значения в контексте, а затем вызовет функцию debugf. void debugf(myCtxStruct * myCtx, char * fmt, ...) ; #define debugf \ if ((myCtx!=NULL) && (myCtx->debugf flag)) \ myCtx->curr lineno = LINE , \ myCtx->curr filename = FILE , \ debugf После этого в шаблоне следует утилита raise application error для обработки ошибок. Это имя, конечно, знакомо каждому разработчику, использовавшему язык PL/SQL. raise application error - встроенная функция PL/SQL, возбуждающая исключительную ситуацию в случае ошибки. Эта функция у нас имеет такое же назначение. Если внешняя процедура вызывает эту функцию раньше, чем завершает работу, возвращаемые внешней процедурой значения игнорируются, а вместо этого в вызывающей среде возбуждается исключительная ситуация. Это позволяет обрабатывать ошибки, возникаю-во внешней процедуре, точно так же, как и в любой PL/SQL-процедуре. static int raise application error(myCtxStruct * myCtx, int errCode, char * errMsg, ...) char msg[8192]; va list ap; va start(ap,errMsg); vsprintf(msg, errMsg, ap) ; va end(ap); debugf(myCtx, raise application error( %d, %s ) , errCode, msg) ; if (OCIExtProcRaiseExcpWithMsg(myCtx->ctx,errCode,msg,0) == OCIEXTPROC ERROR) 1310 Глава 18 debugf(myCtx, He удалось возбудить исключительную ситуацию ); return -1; Дальше следует еще одна функция обработки ошибок, lastOciError. Эта функция получает контекст текущего сеанса и, используя его структуру OCIError, извлекает теки сообщения о последней произошедшей ошибке OCI. Этот текст выбирается в память, выделенную с помощью вызова OCIExtProcAllocCallMemory(). Любая область гамя-ти, выделенная этой функцией, будет автоматически освобождена при выходе из внешней процедуры. Эта функция чаще всего используется в обращении к функции raise application error после неудачного вызова одной из функций OCI. Благодаря ей можно узнать причину возникновения ошибки OCI. static char * lastOciError(myCtxStruct * myCtx) { sb4 errcode; char * errbuf = (char*)OCIExtProcAllocCallMemory(myCtx->ctx, 256); strcpy(errbuf, unable to retrieve message\n ); OCIErrorGet(myCtx->errhp, 1, &errcode, errbuf, 255, OCI HIYPE ERROR); errbuf[strlen(errbuf)-l] = 0; return errbuf; Теперь переходим к основной функции в шаблоне для создания внешних про дур; речь идет о функции init. Она отвечает за формирование и получение информации о состоянии и обработку параметров, установленных в файле инициализации. Это слишком большая функция, чтобы описывать ее полностью, но достаточно простая, если разобраться с используемыми вызовами функций библиотеки OCI. Функция init создает структуру myCtxStruct и вызывает необходимые функции инициализации OCI. Вначале функция получает дескрипторы среды OCI. Она делает это одним из двух способов. Если используются только средства OCI (без прекомпилятора Рго*С), достаточно просто вызвать OCIExtProcGetEnv с передачей контекста внешней процедуры. Эта функция OCI автоматически получает все необходимые дескрипторы. Если используется и библиотека OCI, и прекомпилятор Pro*С, применяется конструкция EXEC SQL REGISTER CONNECT :ctx. Она выполняет настройку на уровне Pro*C При этом все равно необходимо получить дескрипторы среды OCI, но для этого придется использовать вызовы библиотеки Pro*C: SQLEnvGet, SQLSvcCtxGet. Уберите комментарий с используемого метода и закомментируйте другой метод. /*-это надо включать только для внешних процедур, использующих средства Рго*С!! - #define SQLCA INIT EXEC SQL INCLUDE sqlca; static myCtxStruct * init(OCIExtProcContext * ctx) ub1 false = 0;
|
© 2006 - 2025 pmbk.ru. Генерация страницы: 0.067
При копировании материалов приветствуются ссылки. |