Линтер методичка
.pdfклассе CSsqlDS инкапсулируется большинство работы нашего примера с СУБД ЛИНТЕР. Используются обычные вызовы Call-интерфейса, уже изученные нами.
П
Для связи элементов графического интерфейса с данными из БД необходимо
модифицировать стандартные элементы управления так, чтобы они работали через
CDataSourceра .
кт |
Однострочный элемент должен выглядеть примерно так: |
|
ич |
class CMyEdit : public QLineEdit |
|
ес |
||
ко |
{ |
|
е |
|
|
за ... |
||
ня |
public: |
|
ти |
||
void setDS(CDataSource *ds); |
||
е |
||
12 |
void setField(int f) {m_field = f;} |
|
П |
||
ри |
public slots: |
|
ме |
void onDsError(long); |
|
р |
||
ра |
void onDsFullChange(); |
|
зр |
||
void onCurRowChange(long oldrow); |
||
аб |
||
от |
... |
|
ки |
||
пр |
}; |
|
ил |
|
|
ож |
Для многострочного элемента необходимы (на примере с 'QListBox') |
|
ен |
||
а) Функции конвертации номера строки в базе и в элементе: |
||
ия |
||
long rowToDbRow(int); |
||
дл |
||
int dbRowToRow(long); |
||
я |
||
б) Синхронизация изменения положения курсора в источнике данных при |
||
Л |
||
|
||
изменении строки в управляющем элементе. Для этого подписываемся на сигнал: |
||
И |
connect(this, SIGNAL(highlighted(int)), this, |
|
Н |
ТSLOT(slot_highlighted(int)));
Еи пишем следующий код:
Р |
void CMyListBox::slot_highlighted(int) |
|
с |
||
ис |
{ |
|
по |
||
m_ds->setCurRow(rowToDbRow(currentItem())); |
||
ль |
||
зо |
} |
|
ва |
||
ни |
в) Работу многострочного элемента можно построить так, что он не будет содержать |
|
полную копию всех строчек выборки, а только видимую часть. И только при перемещении |
||
ем |
|
|
по строчкам по необходимости брать записи из источника данных. В нашем простом |
||
Qt |
|
|
примере это не рассматривается. |
||
E- |
Указания к практической работе: |
|
!81 |
1. Просмотрите исходные тексты 1-го этапа (директория step1). В директории |
|
mai |
||
l: |
datasource находятся h-файлы с описанием интерфейсных классов и cpp-файлы |
ma rke t@ rele x.r
u
82!
с реализацией классов источника данных. В директории ctrl находятся описания
Пи реализация классов визуальных элементов управления, расширенных до
ра
кт
ич
ес
ко
е
за
ня
ти
е
12
возможности работы с источниками данных. Кроме того, там описан и реализован класс формы нашего тестового приложения. В файле main.cpp содержится код основной программы, которая инициализирует приложение, создает соединение с БД ЛИНТЕР (используются жестко закодированные имя и пароль “SYSTEM/MANAGER”), инициализирует источник данных и создает графическую форму. Обратите внимание на makefile. Там необходимо переопределить переменные LINTER (на путь, в котором установлена СУБД ЛИНТЕР) и QTDIR (путь к установке Qt).
20.Скомпилируйте исполняемый файл (команда make). Обратите внимание, что программа компилируется с отладочной информацией (ключ –g).
21. |
Запустите программу и просмотрите содержимое таблицы AUTO |
в форме |
|
приложения. |
|
22. |
Запустите программу в отладчике gdb . Поставьте точки останова в методах, |
Преализующих работу источника данных с СУБД ЛИНТЕР, например в методах
CSqlDS::retrieve и CSqlDS::getField. Понаблюдайте за исполнением методов,
ри |
|
включая вызовы ЛИНТЕР, по шагам. |
|
||
ме |
|
|
|||
|
|
|
|
||
р |
12.2. Второй этап |
|
|||
ра |
|
||||
Добавим в наш пример возможность обработки сообщений от СУБД ЛИНТЕР. Для |
|||||
зр |
|||||
приложения интересны асинхронный прием сообщения и синхронная обработка. |
|||||
аб |
|
|
|
|
|
Асинхронная обработка имеет ряд системных ограничений и не все вызовы из нее можно |
|||||
от |
|
|
|
|
|
делать (в POSIX стандарте есть список разрешенных вызовов). |
|||||
ки |
Разработаем по нашей проблеме класс |
AsyncManager Наш класс содержит три |
|||
статическиепр |
функции: |
|
|||
ил |
• |
AsyncManager::addNewAsync - регистрация синхронного обработчика для |
|||
ож |
|
асинхронного запроса по определенному каналу; |
|||
ен |
• |
AsyncManager::removeAsync - снятие регистрации синхронного обработчика для |
|||
ия |
|
асинхронного запроса; |
|
||
• |
AsyncManager::onAsyncWork - универсальный асинхронный обработчик, |
||||
дл |
|||||
|
передается как аргумент вызова inter. |
|
|||
я |
|
|
|||
|
|
|
|
Л |
Для синхронизации используем системный (Qt-1.4.x) цикл обработки сообщений. В |
||
И |
|||
|
|
||
таком цикле обязательно стоит вызов типа 'select(.....)', который проверяет состояние по |
|||
указаннымН |
дескрипторам ввода-вывода, в Qt есть класс QSocketNotifier, который позволяет |
зарегистрироватьТ дескриптор ввода-вывода на такую проверку. Мы воспользуемся им.
Создадим 'pipe' и будем его использовать как флаг наличия синхронного обработчика (для
Е
асинхронного запроса) в очереди. Для этого переводим 'pipe' в режим неблокирующей
Р
работы и регистрируем дескриптор чтения (на прослушивание в 'select') таким образом:
m_qNotifier = new QSocketNotifier(m_pipe[0], QSocketNotifier::Read, this);
connect(m_qNotifier, SIGNAL(activated(int)), this, SLOT(SyncProc(int)));
В нашем объекте будем вести два списка объектов типа AsyncObject, которые содержатем информацию о канале, по которому был подан запрос, и синхронной функции-
обработчике. Первый список m_targetList - список поставленных на обработку, второй
Qt
m _ r a i s e L i s t - с п и с о к гото в ы х к с и н х р о н н о й о б р а б от к е. В о б р а б от ч и к е
AsyncManager::onAsyncWork производится перевод из m_targetList в m_raiseList список.
|
|
|
Для активизации 'QSocketNotifier' в 'pipe' записывается 1 байт таким образом: |
|
|
|
|
|
|
E- |
while(write(m_pipe[1], &event, sizeof(event)) < 0) |
|
|
mai |
|
|
|||
|
|
l: |
if (errno != EINTR) |
|
|
ma |
|
|
|
rke |
|
|
|
t@ |
|
rele |
|
||
|
|
x.r |
|
|
|
u |
|
{
Пerrno = 0;
ра |
break; |
|
кт |
||
} |
||
ич |
ес |
Цикл 'while' здесь применяется для гарантированной записи в 'pipe'. Если ‘pipe ’ уже |
||
заполненко |
, то запись пропускается (т.к. любой системный вызов может быть прерван |
||
обработкой по сигналу, см. POSIX). |
|||
е |
Все функции класса, которые модифицируют списки m_targetList и m_raiseList при |
||
за |
|||
с в о е й р а б о т е, д о л ж н ы б л о к и р о в а т ь а с и н х р о н н у ю о б р а б о т к у т.к. |
|||
ня |
|
|
|
AsyncManager::onAsyncWork также модифицируют эти списки. Блокировать необходимо |
|||
ти |
|
SIGIO и SIGUSR1 - эти сигналы могут быть использованы для асинхронной |
|
сигналы |
|||
обработкие |
на клиентской части СУБД ЛИНТЕР. |
||
12 |
Универсальный синхронный обработчик AsyncManager::SyncProc вызывается из |
цикла обработки очереди сообщений при активизации класса QSocketNotifier. В нем из |
||
П |
|
|
списка m_raiseList активизируется синхронные обработчики по каждому каналу. Список |
||
ри |
|
|
m_raiseList и 'pipe' очищается. Цикл ‘while(read(m_pipe[0], &event, sizeof(event)) > 0)’ |
||
ме |
|
|
применяется для гарантированной очистки 'pipe', как и в случае с write. |
||
р |
В приложении создается один объект класса AsyncManager, его конструктор |
|
содержитра |
код инициализации - создание 'pipe' и QSocketNotifier. |
|
зр |
Класс CDbEvent непосредственно связывается с ожидаемым событием Линтера, в |
его конструктор передается имя события. Активизация события в программе |
||
аб |
|
|
осуществляется через метод-сигнал onRaise, интересующиеся объекты должны |
||
от |
|
|
подписаться на этот сигнал (здесь говорится о сигнале, как о термине Qt). |
||
ки |
Вся работа по обработки асинхронного запроса производится через |
|
пр |
||
|
||
функциональность выше описанного класса, синхронный обработчик - статическая функция |
классаил CDbEvent::onSelect. Объект может находиться в 3-х состояниях: Empty/Busy/Ready.
В состояние Busy (ожидания события) объект переводится вызовом метода retrieve, т.е. - |
||
ож |
|
|
асинхронно выполняется запрос |
||
ен |
wait event auto_change; |
|
ия |
||
дл |
Внутри метода retrieve открывается новый курсор, чтобы освободить соединение для |
|
я |
||
|
||
другой работы. Метод clear выполняет запрос |
||
Л |
clear event auto_change; |
|
И |
НМетод destroy переводит объект в состояние 'Empty'.
Т |
Указания к практической работе: |
||
Е |
|||
1. |
Просмотрите исходные тексты 2-го этапа (директория step2). По сравнению с |
||
Р |
|||
|
первым этапом, во-первых, добавлена директория async, в которой находится |
среализация универсального менеджера асинхронной обработки. Во-вторых, в
ис |
директории datasource добавлены исходные тексты класса CDbEvent. В файле |
|
по |
main.cpp добавлена инициализация события. |
|
23. Скомпилируйте исполняемый файл (команда make). |
||
ль |
||
24. Запустите программу и просмотрите содержимое таблицы AUTO в форме |
||
зо |
||
приложения. Затем измените содержимое таблицы AUTO из другой сессии, |
||
ва |
||
например, подав запрос из программы INL . Приложение должно автоматически |
||
ни |
отобразить изменения. |
|
ем |
25. Запустите программу в отладчике gdb . Посмотрите по шагам, как в программе |
|
Qt |
выполняется обработка события БД. |
|
E- |
12.3. Третий этап |
|
!83 |
||
mai |
На этом этапе мы добавим асинхронную обработку запросов в классе CSqlDS. |
|
l: |
||
ma |
|
|
rke |
|
|
t@ |
|
|
rele |
|
|
x.r |
|
|
u |
|
|
В интерфейсе класса CDataSource никаких изменений нет, но объект теперь может |
|
|||||||
находитьсяП |
в 3-х состояниях: Empty/Busy/Ready. Новое состояние 'Busy', как и для объекта |
|
|||||||
класса |
CDbEvent, характеризует объект, находящийся в процессе ожидания ответа на |
|
|||||||
ра |
|
|
|
|
|
|
|
|
|
запрос к СУБД ЛИНТЕР. |
|
|
|
|
|||||
кт |
Добавлен новый метод-сигнал onState - вызывается при изменении состояния |
|
|||||||
ич |
|
||||||||
объекта. Метод retrieve изменен: открывается новый канал для работы (как в CDbEvent) и |
|
||||||||
ес |
|
|
|
|
|
|
|
|
|
запрос посылается асинхронно с переводом в состояние 'Busy'. При получении ответа |
|
||||||||
вызываетсяко |
|
синхронный обработчик - статическая функция класса CSqlDS::onSelect - |
|
||||||
который переводит объект в состояние 'Ready' (вызов метода-сигнала onState) или |
|
||||||||
е |
|
|
|
|
onError. При изменении состояния объекта |
CSqlDS |
в |
|
|
вызывается метод-сигнал |
|
||||||||
за |
|
|
|
|
CDataSource вызывается метод-сигнал |
onFullChange и |
|
||
интерфейсном классе |
|
||||||||
ня |
|
|
|
|
|
|
|
|
|
переустанавливается положение курсора. |
|
|
|
||||||
ти |
Указания к практической работе: |
|
|
|
|||||
е |
|
|
|
||||||
1. |
Просмотрите исходные тексты 3-го этапа (директория step3). Имеются изменения |
||||||||
12 |
|||||||||
|
в директории ctrl. Вместо списка в форму добавлен табличный элемент – класс |
|
|||||||
П |
|
|
|||||||
|
CMyTable, который реализует работу с источником данных простого табличного |
|
|||||||
ри |
|
визуального элемента, позаимствованного из стандартных примеров |
Qt |
|
|||||
ме |
|
(исходные тексты этого элемента находятся в поддиректории table; они взяты из |
|
||||||
р |
|
примеров Qt как есть). Есть изменения также и в директории datasource: они |
|
||||||
|
касаются, в основном, асинхронной обработки. Соответствующим образом |
|
|||||||
ра |
|
|
|||||||
|
модифицирован и файл main.cpp. |
|
|
|
|||||
зр |
26. Скомпилируйте исполняемый файл (команда make). |
|
|
|
|||||
аб |
27. Запустите программу. Обратите внимание, что запрос на выборку данных теперь |
|
|||||||
от |
|
выполняется долго (мы специально вставили перемножение таблицы AUTO |
, |
||||||
ки |
|
чтобы время работы запроса было велико). Но наше приложение при этом |
|
||||||
пр |
|
продолжает работать: оно выдает сообщения о состоянии, реагирует на события |
|
||||||
|
от клавиш и мыши и т.д. Это возможно благодаря асинхронной обработки |
|
|
||||||
ил |
|
|
|
||||||
|
запроса. |
|
|
|
|
||||
ож |
|
|
|
|
|
|
|
|
|
ен |
12.4. Задание для самостоятельной работы |
|
|
|
|||||
ия |
|
|
|
||||||
В качестве самостоятельной работы дополним наш пример функциями |
|
|
|||||||
дл |
|
|
|||||||
модификации (возможность удаления, модификации и добавления записи в источник |
|
||||||||
я |
|
|
|
|
|
|
|
|
|
данных). |
|
|
|
|
|
|
|
||
Л |
Для этого в форме уже предусмотрены кнопки "Обновить", "Вставить", "Удалить". |
|
|||||||
НеобходимоИ |
добавить обработчики нажатия на эти кнопки, которые будут формировать и |
|
|||||||
исполнять запросы UPDATE, UNSERT, DELETE для таблицы AUTO. При этом данные для |
|
||||||||
Н |
|
|
|
|
|
|
|
|
|
этих запросов можно взять из четырех однострочных полей ввода, имеющихся в форме. |
|
||||||||
Т |
|
|
|
|
|
|
|
|
|
Непосредственные вызовы Call-интерфейса ЛИНТЕР можно скрыть в классе CSqlDS, |
|
||||||||
Е |
|
|
|
|
|
|
|
|
|
например, добавить в него метод modify, который будет в качестве параметра принимать |
|
||||||||
текстР запроса, и выполнять этот запрос при помощи команды Call-интерфейса “ “ (четыре |
|||||||||
пробела). Тогда задача обработчиков кнопок будет состоять в том, чтобы сформировать |
|
||||||||
с |
|
|
|
|
(например, функцией sprintf, используя тексты однострочных |
|
|||
требуемый текст запроса |
|
||||||||
ис |
|
|
|
|
|
|
|
|
|
полей) и передать его методу modify. |
|
|
|
||||||
по |
Отметим, что после модификации таблицы старая выборка, сделанная запросом |
|
|||||||
ль |
|
||||||||
|
|
|
|
|
|
|
|
||
SELECT, перестает отображать реальные данные. Простейший способ избежать этого – |
|
||||||||
выбратьзо |
данные заново после их модификации (это позволяет, в том числе, использовать |
|
|||||||
для INSERT,DELETE,UPDATE тот же канал ЛИНТЕР, т.к. результаты старой выборки |
|
||||||||
ва |
|
|
|
|
|
|
|
|
|
SELECT нам все равно уже больше не понадобятся). Заметим, что в нашем примере |
|
||||||||
ни |
|
|
|
|
|
|
|
|
|
данные автоматически будут перечитываться после любой операции модификации |
|
||||||||
ем |
|
|
|
|
|
|
|
|
|
благодаря отслеживанию события БД. |
|
|
|
||||||
Qt |
Учащимся необходимо самостоятельно реализовать и отладить описанную |
|
|||||||
функциональность. Она является самым простым способом обработки модификаций в БД. |
|
||||||||
Более сложный подход описан в следующем разделе. Однако, он требует уже более |
|
||||||||
серьезного программирования, и в рамках данной практики не реализуется. |
|
|
|||||||
E- |
12.5. Пути развития класса – источника данных |
|
|
|
|||||
mai |
|
|
|
||||||
l: |
Что еще не хватает в разработанном классе CDataSource? |
|
|
|
|||||
!84 |
|
|
|
|
|
|
|
|
ma rke t@ rele x.r
u
Очевидно, буферизации данных. Буферизация необходима для того, чтобы исключить лишние обращения к базе данных и производить модификацию данных, не
перечитывая данные из базы, а также поднять производительность обмена между ядром
П
СУБД ЛИНТЕР и клиентом за счет использования команд пакетной загрузки и выгрузки данныхра GETM, PUTM.
кт ич Кроме того, источники данных можно делать связанными в соотношении 'Главный-
подчиненный', организовать фильтрацию/сортировку в памяти, работу с выборкой с полной
ес
буферизацией на клиенте, быстрый поиск записи в выборке и многое другое.
ко
е В AsyncManager можно произвести оптимизацию по вызовам new/delete, если ввести
список свободных объектов и использовать его как буфер свободных объектов.
за
ня
ти
е
12
П
ри
ме
р
ра
зр
аб
от
ки
пр
ил
ож
ен
ия
дл
я
Л
И
Н
Т
Е
Р
с
ис
по
ль
зо
ва
ни
ем
Qt
E!85- mai
l: ma rke t@ rele x.r
u
86!
Практическое занятие 13 Использование прекомпилятора встроенного SQL
Практика 6 часов (Лекция 11)
На занятии будут приведены примеры, иллюстрирующие работу прикладных программ с СУБД ЛИНТЕР, написанных на языке C с использованием встроенного SQL.
Будут рассмотрены следующие вопросы:
•выполнение запросов без параметров;
•обработка ошибок;
•выполнение запросов с параметрами;
•получение данных из выборки;
•обработка результатов запроса с неизвестным форматом ответа;
•выполнение хранимых процедур.
13.1. Компиляция примеров
Компиляция программ, написанных с использованием встроенного SQL, осуществляется в два этапа. Препроцессор pcc поставляется в дистрибутиве СУБД ЛИНТЕР. Результатом его работы является c -файл, который следует компилировать обычным компилятором:
prac13_e1: prac13_e1.pc
$(LINTER)/bin/pcc prac13_e1.pc prac13_e1.c $(CC) -c $(CFLAGS) prac13_e1.c
$(LINKER) prac13_e1.o $(LDKEY)prac13_e1 $(INTLIB) rm -f $@.o
С примерами поставляется makefile.
13.2. Соединение, выполнение запросов без параметров, обработка ошибок
Пример prac13_e1.pc иллюстрирует работу с запросами без параметров. Его алгоритм таков:
•создается соединение;
•делается попытка удаления таблицы PRAC13_T1;
•создается таблица PRAC13_T1;
•вставляются данные;
•делается выборка количества записей в переменную;
•делается выборка поля NAME в переменную buf.
Следует обратить внимание на то, что вставка данных осуществляется в цикле из массива:
EXEC SQL WHENEVER SQLERROR GOTO not_inserted;
EXEC SQL FOR :i EXECUTE IMMEDIATE insert into PRAC13_T1 (id, name) values (:arr_i, 'aaa');
E-mail: market@relex.ru |
ЗАО НПП «РЕЛЭКС» |
http://www.relex.ru |
для этого переменной i присваивается количество повторений, в данном случае, 10. Обработка ошибок осуществляется оператором WHENEVER. Для продолжения
работы используется режим CONTINUE, для перехода на метку – GOTO, для вызова |
|
П |
|
функции – CALL и для завершения приложения – STOP. |
|
ра |
EXEC SQL WHENEVER SQLERROR CONTINUE; |
кт |
|
ич |
Выборка данных в переменную осуществляется следующим образом: |
ес |
EXEC SQL WHENEVER SQLERROR GOTO not_selected; |
ко |
еEXEC SQL SELECT count(*) from PRAC13_T1 into :i;
за |
При этом переменная I должна быть описана в разделе DECLARE SECTION: |
||
ня |
|||
EXEC SQL BEGIN DECLARE SECTION; |
|||
ти |
|||
е |
|
short i = 10; |
|
13 |
|
||
Ис |
EXEC SQL END DECLARE SECTION; |
||
по |
|||
Разрешено включать в запрос переменные: |
|||
ль |
|||
EXEC SQL EXECUTE IMMEDIATE SELECT NAME into :buf from |
|||
зо |
|||
ва |
PRAC13_T1 where ID = :tid; |
||
ни |
|||
Задача 1. Модифицировать данный пример, таким образом, чтобы при |
|||
е |
|||
невозможности соединения приложение завершало свою работу. |
|||
пр |
Задача 2. Модифицировать данный пример, добавив возможность обновления поля |
||
ек |
|||
|
|
||
NAME пользователем в строке по указанному ID. |
|||
ом |
Задача 3. Модифицировать данный пример, добавив полноценный обработчик |
||
ошибокпи , анализирующий переменную ErrPCI_. |
|||
ля |
13.3. Запросы с параметрами |
||
то |
Для выполнения запроса с параметрами необходимо использовать операторы. В |
||
ра |
|||
|
|
||
примере prac13_e2.pc для вставки строк в таблицу и для построения выборки используются |
|||
запросывс |
с параметрами: |
||
тр |
• |
создается соединение; |
|
ое |
• |
делается попытка удаления таблицы PRAC13_T1; |
|
нн |
• |
создается таблица PRAC13_T1; |
|
ог |
• |
создаются два оператора – один для вставки данных, другой – для выборки; |
|
о |
• |
в цикле: пользователь вводит данные одной строки, и выполняется оператор |
|
S |
|
вставки, причем данные передаются как параметры; |
|
Q |
• |
выбирается количество записей из таблицы; |
|
L |
• |
пользователю предлагается указать интервал выводимых записей; |
|
|
• |
в цикле по данному интервалу делается выборка одной записи, чей номер |
|
!87 |
|
принадлежит интервалу. |
|
|
|
||
|
Подготовка операторов происходит следующим образом: |
||
|
EXEC SQL PREPARE ST_INS FROM INSERT INTO PRAC13_T1 (id, |
||
|
name) VALUES (:tid, :tname); |
||
|
EXEC SQL PREPARE ST_SEL FROM SELECT id, name |
||
E- |
into :tid, :tname from (SELECT id, name, rownum as rn FROM |
||
PRAC13_T1) WHERE Rn = :i; |
|||
mai |
|||
l: |
Вставка данных: |
ma rke t@ rele x.r
u
88!
П
ра
кт
ич
ес
ко
е
за
ня
ти
е}
13
Ис
по Получение структуры ответа во встроенном SQL осуществляется при помощи
дескрипторов. Работа с дескрипторами показана в файле примера prac13_e3.pc.
ль
зо
ва
ни
еEXEC SQL ALLOCATE DESCRIPTOR :selectOutDesc;
пр |
• |
пользователь вводит SELECT-запрос; |
|
ек |
|||
• |
по запросу создается оператор; |
||
ом |
|||
EXEC SQL PREPARE ST_SEL FROM :szSQL; |
|||
пи |
|||
ля |
• |
делается описание выходных данных оператора в дескриптор; |
|
то |
EXEC SQL DESCRIBE OUTPUT ST_SEL INTO SQL |
||
ра |
|||
вс |
DESCRIPTOR :selectOutDesc; |
||
тр |
• |
выводится тип и длина полей ответа; |
|
ое |
• |
привязывается к дескриптору буфер, в который следует помещать ответ; |
|
нн |
for (i = 1; i <= colCount; i++) |
||
ог |
|||
о |
{ |
|
|
S |
|
||
|
p = &(buf[shift]); |
||
Q |
|
L |
EXEC SQL GET DESCRIPTOR :selectOutDesc VALUE :i :length = |
|
|
|
LENGTH; |
EXEC SQL SET DESCRIPTOR :selectOutDesc VALUE :i DATA
=:p;
shift += align4(length);
}
|
• |
описывается и открывается статический курсор; |
|
E- |
EXEC SQL DECLARE CUR_SEL CURSOR FOR ST_SEL; |
||
EXEC SQL OPEN CUR_SEL; |
|||
mai |
|||
l: |
• |
осуществляется проход по выборке. |
|
ma |
rke t@ rele x.r u
for (i = 1; ;i++)
П{
ра |
|
memset(buf, 0, sizeof(buf)); |
|
кт |
|
||
|
EXEC SQL FETCH CUR_SEL ABSOLUTE :i USING |
||
ич |
|
||
ес |
DESCRIPTOR :selectOutDesc; |
||
ко |
|
if (ErrPCI_) |
|
е |
|
||
за |
|
{ |
|
ня |
|
|
|
|
if (ErrPCI_ == 3000) printf("No more records\n"); |
||
ти |
|
||
е |
|
else printf("Error code: %d\n", ErrPCI_); |
|
13 |
|
||
Ис |
|
break; |
|
по |
|
} |
|
ль |
|
|
|
зо |
|
printAnswer(); |
|
ва |
|
||
} |
|
||
ни |
|
||
е |
В примере присутствует функция для определения имени типа по его номеру, |
||
возвращенногопр |
дескриптором (нумерация описана в разделе пользовательской |
||
документации |
«Встроенный SQL»). Для совместимости со Sparc-платформами |
||
ек |
|
|
|
предназначена функция align4, вычисляющая адрес, нацело делящийся на 4. |
|||
ом |
Задача 4. Модифицировать пример prac13_e2.pc, изменив алгоритм выборки: |
||
пи |
|||
пользовательский интервал учитывается параметрами в операторе (WHERE Rn >= :num1 |
|||
ля |
|
|
|
and Rn <= :num1). Движение по выборке осуществлять при помощи оператора FETCH. |
|||
то |
Задача 5. Модифицировать пример prac13_e3.pc, добавив обработку типов byte, |
||
varbyte,ра |
varchar, date, decimal, boolean. |
||
вс |
13.5. Вызовы хранимых процедур |
тр |
Встроенный SQL позволяет выполнять хранимые процедуры. Для этого |
|
ое |
||
|
||
предназначен оператор EXECUTE PROCEDURE. |
Алгоритм работы примера таков:
•создается соединение;
•объявляется процедура;
EXEC SQL DECLARE PROCEDURE STRADD(in ch1 char(10); in ch2 char(10)) result int;
• пользователь вводит две строки, в которых находятся целые числа;
!90
П |
• |
вызывается процедура с этими параметрами; |
|
EXEC SQL EXECUTE PROCEDURE :res = STRADD(:ch1, :ch2); |
|||
ра |
|||
кт |
• |
выводится на экран возвращенное значение. |
|
ич |
|
|
|
ес |
Важно, что типы фактических параметров, принимающих результаты (в примере – |
переменная int res), должны совпадать с типами формальных параметров (в примере – |
||
ко |
|
|
result int – результат процедуры). |
|
|
е |
Задача 6. На основе примера prac13_e4.pc, написать программу, проверяющую |
|
за |
||
наличие таблицы, представления или синонима по маске, заданной пользователем (в |
||
ня |
|
select * from $$$SYSRL where $$ |
хранимой процедуре использовать запрос |
||
ти |
|
|
$S13 = :s;). |
|
|
е |
|
|
13
Ис
по
ль
зо
ва
ни
е
пр
ек
ом
пи
ля
то
ра
вс
тр
ое
нн
ог
о
S
Q
L
E- mai l: ma rke t@ rele x.r u