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

1 ... 305 306 307 [ 308 ] 309 310 311 ... 469


1338

Глава 18

21 p filename STRING, p filename INDICATOR short,

22 p lob OCILOBLOCATOR, p lob INDICATOR short,

23 RETURN INDICATOR short); 24

26 function write(p path in varchar2, p filename in varchar2, p lob ini-> bfile)

27 return binary integer

28 as

29 language С name lobToFile library lobtofile lib 3 0 with context parameters (CONTEXT,

31 p path STRING, p path INDICATOR short,

32 p filename STRING, p filename INDICATOR short,

33 p lob OCILOBLOCATOR, p lob INDICATOR short,

34 RETURN INDICATOR short);

3 6 end lob io;

37 /

Package body created.

Интересно отметить, что все три функции сопоставляются одной и той же С-функции. Я не писал отдельные функции для данных типа CLOB, BLOB и BFILE.

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

Код Pro*С для пакета LOB IO

Теперь рассмотрим код для прекомпилятора Pro*С, реализующий библиотеку Iobtoflle lib. Я не буду комментировать универсальный код, рассмотренный в примере, чтобы сократить текст (функции debugf, raise application error, ociLastError,

term и init - такие же, за исключением того, что в функции init в приложениях на ProС используется конструкция EXEC SQL REGISTER CONNECT), и перейду сразу к ко специфическому. Следует отметить, что представленный далее код должен идти после представленного ранее шаблонного кода, и что в шаблоне необходимо убрать комментарии с разделов, связанных с подключением в Рго*С. Начнем с определения всех бок, о которых будет в]даваться сообщение. Этот набор кодов ошибок должен в точности соответствовать кодам ошибок для исключительных ситуаций, заданных в спецификации PL/SQL-пакета. Гарантировать это соответствие невозможно; это всего лишь го-воренность, которой я привык следовать, но следовать ей, определенно, стоит.

#define ERROR FWRITE 20001

#define ERROR REGISTER CONNECT 20002

#define ERROR BLOB IS NULL 20003

#define ERROR FILENAME IS NULL 20004

#define ERROR OPEN FILE 20005

#define ERROR LOB READ 20006



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

Дальше идет внутренняя функция, непосредственно из PL/SQL недоступная, которая будет использоваться основной функцией lobToFile для записи данных в файл. Она также подсчитывает количество байтов, записанных в файл:

static int writeToFile(myCtxStruct * myCtx,

OCIFileObject * output,

char * buff,

int bytes,

int * totalWritten)

ub4 bytesWritten;

debugf(myCtx, Записываем %d байтов в файл , bytes); if (OCIFileWrite(myCtx->envhp, myCtx->errhp, output,

buff, bytes, fcbytesWritten) !*= OCI SUCCESS)

return raise application error (myCtx,

ERROR FWRITE,

Error writing to file %s , lastOciError(myCtx));

if (bytesWritten != bytes)

return raise application error (myCtx,

ERROR FWRITE,

Ошибка записи в файл %d байт, записано только %d байт , bytes, bytesWritten);

*totalWritten+=bytesWritten; return 0;

Первый параметр этой функции - контекст сеанса. Этот контекст должен передаваться всем вызываемым функциям, чтобы можно было использовать такие утилиты, как raise application error. Следующий параметр - выходной файл, в который будут записываться данные. Для выполнения ввода/вывода используются переносимые функции OCIFile. Предполагается, что перед вызовом функции writeToFile соответствующий файл уже открыт. Далее идут указатели на записываемый буфер и количество байтов в буфере. Последней передается переменная-счетчик, в которой хранится общее количество записанных байтов.

Теперь переходим к основной (и последней) функции. Эта функция выполняет все необходимые действия; она принимает локатор большого объекта (независимо от типа объекта - BLOB, CLOB или BFILE) и записывает его содержимое в указанный файл:

#ifdef W NT declspec (dllexport) #endif

int lobToFile(OCIExtProcContext * ctx,

char * path,



1340

Глава 18

short path i,

char * filename,

short filename i,

OCIBlobLocator * blob,

short blob i,

short * return indicator)

Следующая часть кода задает структуру, в которую мы будем выбирать данные. содержит начальное поле размера, в байтах, а затем - пространство данных размером 64 Кбайт. Мы будем выбирать данные из большого объекта порциями по 64 Кба и записывать их на диск. Затем определяются необходимые локальные переменные:

typedef struct long varraw

ub4 len;

text buf[ 6553 6] ; J long varraw;

EXEC SQL TYPE long varraw IS LONG VARRAW(65536);

long varraw data; /* в эту структуру мы будем выбирать данные */ ub4 amt; /* здесь будет храниться количество выбранных */

/* байтов */

ub4 buffsize = sizeof(data.buf); /* это количество байтов */

/* мы запрашиваем */ int offset = 1; /* с какой позиции большого объекта мы */

/* читаем данные */ OCIFileObject* output = NULL; /* файл, в который выполняется запись */ int bytesWritten = 0; /* сколько байтов всего ЗАПИСАНО */

myCtxStruct * myCtx;

*return indicator = OCI IND NULL;

if ((myCtx=init(ctx)) = NULL) return 0;

Начнем с проверки индикаторов пустых значений. Если установлена любая из индикаторных переменных, необходимо вернуть сообщение об ошибке. Это показ1вает, почему важно всегда передавать индикаторные переменные во внешние процедуры на языке С. Никогда нельзя быть уверенным, что пользователь случайно не передал пустое значение. Попытка без предварительной проверки обратиться к файлу с указанным именем или к большому объекту, которые окажутся пустыми, может закончиться строфически (внешняя процедура закончится неудачно), поскольку параметры окажутся не проинициализированными.

if (blob i == OCI IND NULL) {

raise application error (myCtx,

ERRQR BLOB IS NULL,

Функции lobToFile передан стой большой объект; ->недост аргумент ) ;

else if (filename i == OCI IND NULL path i = OCI IND NULL)



1 ... 305 306 307 [ 308 ] 309 310 311 ... 469

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