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

1 ... 295 296 297 [ 298 ] 299 300 301 ... 469


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;



1 ... 295 296 297 [ 298 ] 299 300 301 ... 469

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