Линтер методичка
.pdfПрактическое занятие 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
Задача 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))