Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Линтер методичка

.pdf
Скачиваний:
78
Добавлен:
21.05.2015
Размер:
1.38 Mб
Скачать

Практическое занятие 9 Знакомство с CALL-интерфейсом

Практика 2 часа (Лекции 7,8)

На данном занятии мы освоим основы использования CALL-интерфейса СУБД ЛИНТЕР, на примере открытия соединения, выполнения SELECT-запросов, обработки ответов и закрытия соединения. На этом примере мы получим общие навыки подключения CALL-интерфейса и использования функции inter.

9.1. Сборка программы с CALL-интерфейсом

Для сборки программы с CALL-интерфейсом необходимо:

определить символ

_VER_MAX=<версия ЛИНТЕР>

где <версия ЛИНТЕР> - это число, полученное <как первый номер версии>*100 + <второй номер версии>*10; например, для 5.7 это будет 570, а для 5.9 – 590;

прописать пути для директивы #include в директорию intlib

дистрибутива

ЛИНТЕР;

 

для Windows надо определить еще символ препроцессора INTER_MSWINDOWS;

включить в сборку библиотеку intlib:

в среде Windows это может быть статическая библиотека inter325.lib, расположенная в одной из поддиректорий директории intlib (в зависимости от компилятора), либо динамически подключаемая библиотека inter325.dll, соответствующая библиотека импорта inter325.lib находится в директории intlib/ lib;

в среде Unix просто используется объектный файл intlib.o, расположенный в поддиректории intlib дистрибутива;

либо вместо подключения библиотеки можно подключить непосредственно исходный текст CALL-интерфейса intlib/intlib.c.

В среде Windows в дистрибутиве ЛИНТЕР имеется файл Definition, который конфигурируется при установке системы. Он включает все необходимые определения, и может быть просто включен в make-файл.

Примеры использования CALL-интерфейса и соответствующие make-файлы имеются в директориях samples/call и samples/c дистрибутива ЛИНТЕР.

Задание: Собрать примеры простейшего использования CALL-интерфейса, поставляемые вместе с ЛИНТЕР.

Указания:

Перейдите в поддиректорию samples/c дистрибутива ЛИНТЕР.

Изучите исходный текст примера step/step.c. Он содержит вызовы команд CALLинтерфейса “OPEN”, “SLCT”, “GETN” и “CLOSE”, печатая простую выборку, сделанную оператором SELECT.

Изучите содержимое make-файла (он содержит команды для сборки всех примеров, расположенных в поддиректории samples/c).

Соберите примеры:

для Unix, подайте команду make;

 

для Windows, подайте команду nmake /f makefile.vc

(предполагается

 

использование Microsoft Visual C++).

 

52!

П

Убедитесь в том, что запущена СУБД ЛИНТЕР на демонстрационной БД,

 

содержащейра

таблицу PERSON.

 

 

кт

Запустите исполняемый файл примера step и просмотрите результаты.

 

 

ич

9.2. Разработка собственного примера

 

 

ес

Задание: Используя демонстрационный пример из состава

СУБД

ЛИ

ко

 

 

CALL

-

необходимо разработать и отладить собственную программу, использующую

интерфейс для выборки данных.

 

 

за

Все задачи связаны с таблицами PERSON, AUTO или FINANCE демонстрационной

БД ЛИНТЕР.

 

 

 

ня

Задача 1. Разработать программу, которая запрашивает начальные буквы имени

 

ти

 

человека (поле PERSON.NAME), и выводит данные обо всех людях, имя которых

 

е 8

 

 

 

 

начинается с этих букв и о марке (MAKE), модели (MODEL) и серийном номере (SERIALNO)

П

 

 

 

 

автомобилей (таблица AUTO), принадлежащих каждому человеку (таблицы PERSON и

 

AUTOри

связаны по полю PERSONID). При этом данные о человеке должны выводиться

 

одной строкой, затем несколько строк о его автомобилях, затем данные о следующем

 

ме

 

 

 

 

человеке и т.д.

 

 

р

Задача 2. Разработать программу, которая запрашивает начальные буквы марки

 

со

 

автомобиля (AUTO.MAKE) и выполняет запрос на выборку данных, соответствующих этим

зд

маркам, после чего печатает количество ответов и запрашивает номер строки, которую

нандо отобразить. После ввода номера строки, программа должна отобразить данные этой строкиия , и снова запросить новый номер (до тех пор, пока пользователь не введет

недопустимое значение номера).

за щ Задача 3. Разработать программу, которая запрашивает название кредитной карты

(первые несколько букв поля CRDITCRD таблицы FINANCE) и выводит имена всех людей

и

(PERSON.NAME), владеющих картой данного типа (таблицы PERSON и FINANCE связаны пощполю PERSONID). При этом программа должна запрашивать порядок сортировки имен

приен печати: по возрастанию или по убыванию. Напечатав список имен, программа снова

должна запросить порядок вывода имен, после чего выводит их (возможно, уже в другом

но

 

 

порядке) и так далее, пока пользователь не введет команду выхода.

й

Задача 4. Разработать программу, которая запрашивает уникальный идентификатор

ба

 

 

человека (PERSON.PERSONID). После ввода идентификатора программа выводит имя

человеказы

(PERSON.NAME) и выдает список всех автомобилей, которыми владеет данный

человек

(произвольный набор колонок из таблицы AUTO по желанию разработчика,

да

 

 

таблицы AUTO и PERSON связаны по полю PERSONID). Далее программа запрашивает

нн

 

новый идентификатор и т.д., пока пользователь не введет –1.

ы

Задача 5. Разработать программу, которая запрашивает величину жалованья

х

 

человека (поле SALARY таблицы PERSON). После этого программа должна выдать

информацию (идентификатор (PERSONID), имя (NAME), должность (JOB ) и жалованье) о десяти людях, жалование которых наиболее близко к введенному значению.

E- mai l: ma rke t@ rele x.r u

Практическое занятие 10 Углубленное изучение CALL-интерфейса

Практика 6 часов (Лекция 9)

На занятии будут приведены примеры, иллюстрирующие работу с СУБД ЛИНТЕР через прикладной интерфейс низкого уровня Intlib (CALL-интерфейс).

Будут рассмотрены следующие вопросы:

обработка ошибок с использованием GETE;

использование DML/DDL запросов;

работа с BLOB-столбцами;

работа с подчиненными курсорами;

обработка транзакций;

получение структуры ответа;

асинхронное выполнение запроса.

10.1. Использование DML/DDL запросов, обработка ошибок

Алгоритм работы примера prac10_e1.c таков:

1.Открывается канал.

2.Удаляется таблица AUTO, и при ошибке выводится текст с помощью команды

GETE.

3.Создается таблица AUTO, и при ошибке выводится текст с помощью команды

GETE.

4.Закрывается канал.

Следует обратить внимание на то, что запросы DML/DDL (все, кроме SELECT), подаются с четырьмя пробелами в поле Command:

memcpy(Cbl.Command," ",4); /* Non SELECT command */

inter(&Cbl,NULL,"drop table auto;",NULL,NULL);

Для получения информации о произошедшей ошибке во время компиляции или выполнения запроса, предназначена команда GETE. В примере рассматривается применение данной команды для получения текстового сообщения от ядра о произошедшей ошибке (функция PrintError).

memcpy(pCBL->Command,"GETE",4);

/* Get error text */

pCBL->RowId = pCBL->CodErr;

pCBL->LnBufRow = MAXSTRLEN;

inter(pCBL,NULL,NULL,NULL,szErrorText);

if (pCBL->CodErr != NORMAL)

printf("Ошибка обработки GETE: %ld\n", pCBL->CodErr);

else {

54!

П

realLen = (pCBL->LnBufRow < realLen - 1) ? pCBL->LnBufRow

ра

: realLen;

кт

printf("Сообщение: %s\n", szErrorText);

ич

}

 

ес

 

ко

Для получения текстового сообщения заполняется поле RowId номером ошибки

ЛИНТЕР, LnBufRow длиной буфера под сообщение. Адрес буфера передается как

е

 

 

последний параметр функции inter.

за

При успешном завершении функции в буфере находится текстовое сообщение об

ня

 

 

ошибке, которое в примере выводится на экран.

ти

Для демонстрации примера необходимо, чтобы существовала таблица ERRORS с

описаниямие

ошибок. Если данная таблица отсутствует, то сообщение об ошибках будет

10.

 

 

выглядеть так: Linter return code: 2202.

Уг

10.2. Работа с BLOB-столбцами

лу

Алгоритм работы примера prac10_e2.c таков:

бл

1.

Открывается канал.

ен

2. Делается попытка создания таблицы TFILE.

но

3.

Предлагается меню, в котором:

е

в таблицу добавляется запись, в BLOB -поле которой загружается указанный

из

 

пользователем файл;

уч

 

делается выборка из таблицы, и выгружаются данные BLOB -поля в файл из

ен

 

строки, указанной пользователем.

ие

18. Закрывается канал.

C

 

 

A

Следует обратить внимание, на то, что при занесении BLOB-данных можно указать

типL(целое число), передаваемое в параметре RowId.

L-

 

memcpy(pCbl->Command,"AOBJ",4);

ин

 

те

 

pCbl->RowId = 0;

рф

 

pCbl->LnBufRow = realLen;

ей

 

 

inter(pCbl,NULL,NULL,NULL,buf);

са

 

При получении BLOB-данных следует иметь в виду, что передаваемая в параметре RowId позиция начинается с единицы.

long beginPos = 1;

memcpy(pCbl->Command,"GOBJ",4); pCbl->RowId = beginPos; pCbl->LnBufRow = blobPortion; inter(pCbl,NULL,NULL,NULL,buf);

beginPos += realLen;

E-

Работы с данными из BLOB-столбца с минимальным номером используются

команды AOBJ, COBJ и GOBJ. Для работы с другими BLOB-столбцами (с указанием mai

номера) следует использовать команды ABLB, CBLB и GBLB. l:

ma Обучаемым необходимо самостоятельно решить одну из следующих задач.

rke t@ rele x.r u

memcpy(Cursor[i].Command,"OCUR",4);
/* Open cursor */
E- mai l: ma rke t@ rele x.r u
фиксируются изменения по любому из курсоров;
откатываются изменения по любому из курсоров; 19. Закрывается канал.
Студенты должны попробовать выполнять разные действия по разным курсорам и посмотреть, как работает механизм подчиненных курсоров.
Следует обратить внимание на то, что номер родительского канала устанавливается в CBL дочернего Следующим образом:
Cursor[i].NumChan = Cbl.NumChan;
Cursor[i].PrzExe = M_OPTIMISTIC;
делается выборка из таблицы по любому из курсоров;
55!
из таблицы удаляются все записи по любому из курсоров;
в таблицу добавляется запись по любому из курсоров;
4. Предлагается меню, в котором:
3. Открываются два курсора (в оптимистичном режиме обработки транзакций).
2. Делается попытка создания таблицы PRAC12_T1.
1. Открывается канал.
10. Как уже известно, клиентское приложение для работы с БД должно открыть канал связиУг (соединение). При открытии канала приложение должно указать имя ЛИНТЕРсервералу , с которым должно быть установлено соединение, а также регистрационные
данные для проверки санкционированного доступа (имя пользователя и пароль, под
бл
которыми приложение будет зарегистрировано как пользователь БД).
ен Через соединение могут быть открыты подчиненные каналы, называемые
но
курсорами. Для открытия курсора приложению уже не нужно указывать регистрационные данные – курсоры наследуют эту информацию от соединения, которому они подчинены. Этоиз удобно использовать, когда приложение должно обрабатывать различные запросы,
направляемые к одной и той же БД: можно не открывать несколько соединений, а
уч
использовать несколько курсоров.
ен Механизм соединений и курсоров используется СУБД ЛИНТЕР для управления
ие
транзакциями. Изменения данных в БД, прошедшие по некоторому курсору, могут фиксироватьсяC (откатываться) независимо от работы по другим курсорам соединения, однакоA фиксация/откат по соединению вызовет фиксацию/откат по всем подчиненным
курсорам.
L
L- Пример prac10_e3.c иллюстрирует работу канала и двух подчиненных курсоров.
Алгоритм его работы таков:
ин
те
рф
ей
са

Задача 1. Модифицировать данный пример, добавив возможность очистки всей таблицы и удаления указанных записей.

П

Задача 2. Модифицировать данный пример, добавив возможность очистки

содержимого BLOB-ячейки и добавления данных в конец существующей BLOB-ячейки.

ра

Задача 3. Модифицировать данный пример, добавив в таблицу поле FSOURCE, в

кт

 

 

котором будет располагаться исходный текст данного исполняемого файла (если он

существуетич

в директории данного файла). Например, пользователь указывает имя файла /

home/linter/prac10/prac10_e2, тогда добавляется новая запись; в столбец FCONTENT

ес

 

 

загружается этот файл, а в столбец FSOURCE добавляется файл /home/linter/prac10/

ко

 

 

prac10_e2.c.

е

Задача 4. Модифицировать данный пример, следующим образом: если для

за

 

 

указанного имени файла существует файл *.c (с расширением ‘c’), то он добавляется

следующейня

строкой и ему присваивается тип 1. Если существует файл *.h , то он также

добавляетсяти новой строкой и ему присваивается тип 2.

е10.3. Работа с подчиненными курсорами, обработка транзакций

ен
таковно :

56!

П

inter(Cursor + i,NULL,NULL,NULL,NULL);

ра

Необходимо иметь в виду, что управляющий блок Cursor[I] перед этим должен быть

очищен, чтобы другие поля не содержали неправильной информации (например, если в

кт

 

 

поле Node окажется «мусор», то результатом операции будет 1001). Другой вариант –

ич

 

 

просто скопировать содержимое управляющего блока основного соединения в

управляющийес

блок курсора перед установкой специфических полей.

ко

Для самостоятельного решения предлагается одна из задач:

е

Задача 5. Модифицировать данный пример, добавив возможность ввода

пользователем режимов обработки транзакций. Внимательно посмотреть отличия в работе

за

 

примера в оптимистичном и пессимистичном режимах.

ня

Задача 6. Модифицировать данный пример, добавив возможность отката и фиксации

ти

изменений по главному каналу. Выяснить, что происходит с незавершенными дочерними

е

транзакциями при фиксации или откате родительской.

10. 10.4. Получение структуры ответа

Уг лу В случае, когда структура ответа неизвестна (например, идет выполнение запроса,

заданного пользователем), необходимо выяснить структуру ответа. Для этого

бл

предназначена команда GETA.

Пример prac10_e4 иллюстрирует работу данной команды. Алгоритм его работы

е

1.

Открывается канал.

из

2.

Пользователь вводит SELECT-запрос.

уч

3.

Запрос исполняется.

ен

4.

Выбирается количество столбцов в ответе.

ие

5.

Выбирается описание столбцов.

C

6.

Закрывается канал.

A

 

 

L

Сборка примера должна осуществляться с указанием используемой версии СУБД

ЛИНТЕР:

 

L-

 

 

ин

gcc prac10_e4.c -I /export/home/lindesk/linter5923/linter/

те

intlib/ /export/home/lindesk/linter5923/linter/intlib/

рф

ей

intlib.o -o prac10_e4 -lsocket -D_VER_MAX=590

са

В данном примере описание столбцов выбирается по одному, хотя более

эффективно было бы выбирать группами по N элементов. N = <максимальный размер

ответа> /

<размер дескриптора столбца, или sizeof(GETA_OUT). Максимальный размер

ответа равен 4 Кб.

Задача 7. Модифицировать данный пример, чтобы выборка дескрипторов столбцов осуществлялась блоками.

10.5. Асинхронное выполнение запроса

В случае, когда выполнение запроса может занять достаточно много времени, имеет смысл использовать асинхронные запросы. Для этого с запросом передается адрес функции, которая будет вызвана по окончанию запроса.

 

Алгоритм работы примера prac10_e5 таков:

 

1.

Открывается канал и подчиненный курсор.

 

2.

Делается попытка создать таблицу PRAC10_T1.

 

3.

Создается событие на добавление строки в таблицу.

 

4.

По курсору выполняется команда ожидания события, которая будет

 

 

обрабатываться асинхронно.

E-

5.

Пользователь в любой момент может подать запрос на вставку данных в таблицу.

mai

6.

Происходит событие, завершается обработка запроса по курсору, и управление

l:

 

передается в процедуру асинхронной обработки.

ma rke t@ rele x.r

u

7. Поскольку из асинхронного обработчика можно вызывать функцию inter только асинхронно, то очистка события также происходит в асинхронном режиме.

П8. Закрывается соединение, и освобождаются ресурсы библиотеки.

ра

Асинхронный обработчик, как видно из вывода примера, срабатывает до окончания

кт

синхронной операции вставки данных в таблицу.

ич

Вставка по каналу 4... – синхронная команда на вставку

ес

ко

стартовала

 

е

Вставка выполнена – сработал асинхронный обработчик

за

ня

ожидания события

 

ти

Очистка события...готово – произошла очистка события

е

10.

(удаление из очереди)

 

Уг

Вставка выполнена. – завершилась синхронная команда вставки

лу

записи.

 

бл

 

ен

Заметим, что событие инициируется в момент любой вставки, и остается актуально

до тех пор, пока его не очистить. Поэтому если сначала выполнить вставку, а затем

но

 

 

включить режим ожидания, то ожидание события сразу же получит ответ (т.к. событие было

е

 

 

выставлено предыдущей вставкой).

 

из

В коде примера следует обратить внимание на то, как передается адрес процедуры

иучуказывается флаг асинхронности:

 

ен

memcpy(Cbl->Command,"

",4);

ие

C

Cbl->LnBufRow = 0;

 

A

Cbl->PrzExe = Cbl->PrzExe | Q_ASYNC;

L

L-

inter(Cbl,NULL,"clear event INS_T1;", onEventCleared,

ин

NULL);

 

те

 

рф

Задача 8. Модифицировать данный пример, чтобы при удалении данных в

специальную таблицу вставлялись данные о количестве удаленных строк и времени

ей

удаления (реализовать это, используя CALL -интерфейс и асинхронную обработку событий

(без триггеров)).

са

57!

E- mai l: ma rke t@ rele x.r u

58!

Практическое занятие 11 Основные приемы использования LinAPI

Практика 2 часа (Лекция 10)

На занятии будут приведены примеры, иллюстрирующие работу с СУБД ЛИНТЕР через прикладной интерфейс LinAPI.

11.1. Настройки компилятора

Для компиляции файлов с примерами необходимо указывать компилятору путь к файлам “linapi.h”, “decimals.h”, “tick.h”, а компоновщику к библиотекам “linapi”, “decimals”, “tick”.

Эти файлы и библиотеки поставляются в директории linter/intlib.

К примеру, в UNIX-системах, команда на компиляцию файла примера ins_linapi.c может выглядеть так:

gcc -I /export/home/lindesk/linter5923/linter/intlib/ ins_linapi.c -llinapi -ldecimals -ltick -L /export/home/ lindesk/linter5923/linter/intlib/ -lsocket –lm –o ins_linapi

11.2. Открытие соединения, курсора и выполнение запроса

Ниже представлен пример (prac12_e2.c ), в котором консольное приложение делает попытку создать соединение, открыть курсор, и подать по нему команду по удалению и созданию таблицы, выполнить несколько операций по вставке данных.

#include <stdio.h> #include <stdlib.h>

#include "linapi.h"

 

#if defined(VXWORKS)

/* 05.03.02 */

#include "vxstart.h"

 

#endif

 

#ifdef _BCPP_

 

extern unsigned _stklen = 16383;

 

#endif

 

/* function for error processing for LinAPI */ void processing_error(LONG ret_cod,

WORD con_id,

E-mail: market@relex.ru

ЗАО НПП «РЕЛЭКС»

http://www.relex.ru

 

WORD cur_id,

П

WORD stmt_id,

ра

char * message)

кт

{

ич

ес

LONG lRet;

ко

еLONG apierr = 0, error = 0, syserr = 0;

за

 

ня

 

ти

if ( ret_cod == LINAPI_ERROR )

е

{

11.

Ос

/* getting error codes for required object */

но

вн

if (lRet = LINTER_Error(con_id, cur_id, stmt_id,

ые

&apierr, &error, &syserr, NULL, NULL))

пр

ие

printf("diagnostic error %ld\n",lRet);

м

else

ы

ис

{

по

ль

printf("ApiErr = %ld, LinErr = %ld, SysErr = %ld\n%s

зо

\n",

ва

apierr, error, syserr, message);

ни

я

if ( (apierr == eLinterError) && error > 2000 && error

Li

n

< 3000)

A

{

PI

/* getting string and position if syntax error is */

!59

printf("Syntax error : line %d, position %d\n",

 

 

(short)syserr, *(short*)((char*)&syserr +2));

 

}

 

}

 

LINTER_CloseAPI(); /* Free library resource */

 

exit(1);

 

}

E-

else

mai

printf("Return code = %ld\n",ret_cod);

l:

ma

 

rke

 

t@

 

rele

 

x.r

 

u

 

60!

П

ра

кт

ич

ес

ко

е

за

ня

ти

е

11.

Ос

но

вн

ые

пр

ие

м

ы

ис

по

ль

зо

ва

ни

я

Li n A PI

}

#if defined(VXWORKS)

/* 05.03.02 */

MainStart(apidata, 32*1024, UninitLinterClient)

#else

int main(void)

#endif

{

WORD

nConn;

/* connection identifier */

WORD

nCurs;

/* cursor identifier

*/

LONG

lRet;

/* return code */

 

/* Establish connection */

printf("\nConnect\n");

if (lRet = LINTER_Connect("SYSTEM", 0, "MANAGER", 0, NULL, mAutocommit, &nConn))

processing_error(lRet, nConn, 0, 0, "ERROR Linter_Connect");

/* cursor opening for query processing */

printf("Open cursor\n");

if (lRet = LINTER_OpenCursor(nConn, &nCurs, NULL, 0, mAutocommit))

processing_error(lRet, nConn, 0, 0, "Error open cursor");

E- mai l: ma rke t@ rele x.r u

LINTER_ExecuteDirect(nCurs, "drop table PRAC12_STUDENT;", 0, NULL,NULL);

if (lRet = LINTER_ExecuteDirect(nCurs, "create table PRAC12_STUDENT(num int not null primary key, fio char(250) not null, skurs int default 1, sgroup int default 1 );", 0, NULL,NULL))