ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 12.04.2021
Просмотров: 1865
Скачиваний: 3

!
86
!
!
E-mail: market@relex.ru
ЗАО
НПП
«
РЕЛЭКС
»
http://www.relex.ru
Практическое
занятие
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');

!
!
П
ра
кт
ич
ес
ко
е
за
ня
ти
е
13
Ис
по
ль
зо
ва
ни
е
пр
ек
ом
пи
ля
то
ра
вс
тр
ое
нн
ог
о
S
Q
L
!
87
E-
mai
l:
ma
rke
t@
rele
x.r
u
для
этого
переменной
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;
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;
•
создаются
два
оператора
–
один
для
вставки
данных
,
другой
–
для
выборки
;
•
в
цикле
:
пользователь
вводит
данные
одной
строки
,
и
выполняется
оператор
вставки
,
причем
данные
передаются
как
параметры
;
•
выбирается
количество
записей
из
таблицы
;
•
пользователю
предлагается
указать
интервал
выводимых
записей
;
•
в
цикле
по
данному
интервалу
делается
выборка
одной
записи
,
чей
номер
принадлежит
интервалу
.
Подготовка
операторов
происходит
следующим
образом
:
EXEC SQL PREPARE ST_INS FROM INSERT INTO PRAC13_T1 (id,
name) VALUES (:tid, :tname);
EXEC SQL PREPARE ST_SEL FROM SELECT id, name
into :tid, :tname from (SELECT id, name, rownum as rn FROM
PRAC13_T1) WHERE Rn = :i;
Вставка
данных
:

!
88
П
ра
кт
ич
ес
ко
е
за
ня
ти
е
13
Ис
по
ль
зо
ва
ни
е
пр
ек
ом
пи
ля
то
ра
вс
тр
ое
нн
ог
о
S
Q
L
!
!
E-
mai
l:
ma
rke
t@
rele
x.r
u
scanf("%d %s", &tid, tname);
EXEC SQL EXECUTE ST_INS USING :tid, :tname;
Выборка
данных
:
for (i = n1; i <= n2; i++)
{
EXEC SQL EXECUTE ST_SEL USING :i into :tid, :tname;
printf("\t%d.\t%d\t%s\n", i, tid, tname);
}
13.4.
Получение
структуры
ответа
Получение
структуры
ответа
во
встроенном
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++)
{
p = &(buf[shift]);
EXEC SQL GET DESCRIPTOR :selectOutDesc VALUE :i :length =
LENGTH;
EXEC SQL SET DESCRIPTOR :selectOutDesc VALUE :i DATA
= :p;
shift += align4(length);
}
•
описывается
и
открывается
статический
курсор
;
EXEC SQL DECLARE CUR_SEL CURSOR FOR ST_SEL;
EXEC SQL OPEN CUR_SEL;
•
осуществляется
проход
по
выборке
.

!
!
П
ра
кт
ич
ес
ко
е
за
ня
ти
е
13
Ис
по
ль
зо
ва
ни
е
пр
ек
ом
пи
ля
то
ра
вс
тр
ое
нн
ог
о
S
Q
L
!
89
E-
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_);
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.
Работа
данного
оператора
иллюстрируется
в
примере
prac13_e4.pc.
Для
демонстрации
данного
примера
необходимо
создать
тестовую
процедуру
,
при
помощи
,
например
,
утилиты
inl:
create procedure STRADD(in ch1 char(10); in ch2 char(10))
result int
code
return tointeger(ch1) + tointeger(ch2);
end
Алгоритм
работы
примера
таков
:
•
создается
соединение
;
•
объявляется
процедура
;
EXEC SQL DECLARE PROCEDURE STRADD(in ch1 char(10); in ch2
char(10)) result int;
•
пользователь
вводит
две
строки
,
в
которых
находятся
целые
числа
;

!
90
П
ра
кт
ич
ес
ко
е
за
ня
ти
е
13
Ис
по
ль
зо
ва
ни
е
пр
ек
ом
пи
ля
то
ра
вс
тр
ое
нн
ог
о
S
Q
L
!
!
E-
mai
l:
ma
rke
t@
rele
x.r
u
•
вызывается
процедура
с
этими
параметрами
;
EXEC SQL EXECUTE PROCEDURE :res = STRADD(:ch1, :ch2);
•
выводится
на
экран
возвращенное
значение
.
Важно
,
что
типы
фактических
параметров
,
принимающих
результаты
(
в
примере
–
переменная
int res),
должны
совпадать
с
типами
формальных
параметров
(
в
примере
–
result int –
результат
процедуры
).
Задача
6.
На
основе
примера
prac13_e4.pc,
написать
программу
,
проверяющую
наличие
таблицы
,
представления
или
синонима
по
маске
,
заданной
пользователем
(
в
хранимой
процедуре
использовать
запрос
select * from $$$SYSRL where $$
$S13 = :s;
).