Шрифт:
Интервал:
Закладка:
Типы ARRAY и SQL
Поскольку в Firebird не существует никакого синтаксиса динамического SQL для обработки типов ARRAY, выполнение DML и поиск таких типов из интерфейсов динамического SQL (DSQL) не является простым делом. API Firebird содержит структуры и функции, позволяющие динамическим приложениям работать с ними напрямую. Некоторые компоненты доступа к данным RAD (например, iBObject, использующиеся в продуктах Borland Delphi и Kylix) содержат классы, инкапсулирующие эту функциональность API в виде свойств и методов клиентской стороны.
ESQL, который не использует структуры и вызовы функций API, поддерживает некоторый статический синтаксис SQL для обработки типов ARRAY и интеграции их с массивами, объявленными во включающем языке.
Для динамических и статических приложений есть подходящее, хотя и не всегда осуществимое решение: чтение данных массива в хранимой процедуре и возвращение значений в том виде, в каком клиентское приложение может их использовать. Позже в разд. "Ограниченный доступ динамического SQL" будет приведен пример.
Когда использовать тип массива
Использование массивов является подходящим, когда:
* элементы данных естественно принимают вид множества данных одного типа;
* весь набор элементов данных в одном столбце базы данных должен быть представлен и должен управляться как одно целое вместо того, чтобы сохранять каждый элемент в отдельном столбце;
* к каждому элементу также должен быть индивидуальный доступ;
* не требуется доступ к индивидуальным значениям в триггерах или хранимых процедурах, либо у вас есть внешние функции для реализации такого доступа.
Подходящие типы элементов
Массивы могут содержать элементы любого поддерживаемого Firebird типа за исключением BLOB. Массивы массивов не поддерживаются. Все элементы конкретного массива имеют один и тот же тип данных.
Определение массивов
Массив может быть определен как домен (с использованием CREATE DOMAIN) или как столбец в операторе CREATE TABLE или ALTER TABLE. Определение домена или столбца как массива похоже на определение любого другого такого объекта, здесь только добавляется указание размерности массива. Размерность массива заключается в квадратные скобки и следует за спецификацией типа данных.
Например, следующий оператор определяет обычный символьный столбец и столбец в виде одноразмерного символьного массива, содержащего восемь элементов:
CREATE TABLE ATABLE (ID BIGINT,
ARR_CHAR(14)[8] CHARACTER SET OCTETS);
/* хранит 1 строку по 8 элементов */
Многомерные массивы
Firebird поддерживает многомерные массивы размерностью от 1 до 16. Например, следующий оператор определяет три столбца целочисленных массивов с двумя, тремя и четырьмя размерностями:
CREATE TABLE BTABLE (
/* хранит 4 строки по 5 элементов = 20 элементов */
ARR_INT2 INTEGER[4,5],
/* 6 уровней, по 4 строки по 5 элементов = 120 элементов */
ARR_INT3 INTEGER [4,5,6],
/* 7 ярусов, по 6 уровней в 4 строки по 5 элементов = 840 элементов */
ARR_INT6 INTEGER[4,5,6,7] ) ;
Firebird хранит многомерные массивы в порядке развертывания по строкам. В некоторых языках, например FORTRAN, ожидается, что массивы хранятся в порядке развертывания по столбцам. В таких случаях позаботьтесь о правильной трансляции порядка элементов между Firebird и используемым языком программирования.
Задание диапазона значений индексов для размерностейРазмерности массивов в Firebird задаются в виде верхней и нижней границ, называемых списком индексов. По умолчанию размерности основаны на 1 - первый элемент массива из n элементов имеет индекс 1, второй элемент имеет индекс 2, а последний элемент индекс n. Например, следующий оператор создает таблицу со столбцом, который является массивом четырех целых:
CREATE TABLE TABLEC (ARR_INT INTEGER[4]);
Индексы этого массива 1, 2, 3 и 4.
Пользовательские (явные) границы индексовПользовательская установка верхней и нижней границы может быть явно определена для каждой размерности массива при создании столбца ARRAY. Например, программисты С и Pascal, знакомые с массивами, основанными на нуле, могут создавать столбцы массивов с нулевой нижней границей для полного соответствия со структурой массивов в коде приложения.
Требуются нижняя и верхняя граница размерности при определении пользовательских границ. Используется следующий синтаксис:
[ нижняя:верхняя]
Следующий пример создает таблицу с одноразмерным, основанным на нуле столбцом массива:
CREATE TABLE TABLED
(ARR_INT INTEGER[0:3]);
/* индексы 0, 1, 2, и 3. */
Каждое задание границ размерности отделяется от следующего запятой. Например, следующий оператор создает таблицу со столбцом массива размерности два, где обе размерности основаны на нуле:
CREATE TABLE TABLEE
(ARR_INT INTEGER[0:3, 0:3]);
Хранение столбцов массивов
Как и другие типы данных, реализованные как BLOB, Firebird хранит идентификатор массива в столбце таблицы базы данных, который ссылается на страницу, содержащую фактические данные.
ОбновленияКак и в случае других типов BLOB, сервер Firebird не может последовательно просматривать индивидуальные элементы при условном обновлении. При этом в одиночном операторе DML возможно изолировать один элемент или набор последовательных элементов, называемый фрагментом, и передавать этот фрагмент для обновления.
ДобавленияОператор INSERT не может оперировать с фрагментами. Когда строка добавляется в таблицу, содержащую столбцы массивов, необходимо конструировать и заполнять массив целиком до передачи его INSERT.
Доступ к данным массива
Некоторые интерфейсы приложений инкапсулируют функции и дескрипторы API, ограниченный доступ для чтения возможен из хранимых процедур.
Дескриптор массиваAPI предоставляет структуру дескриптора массива для передачи серверу массива или фрагмента массива для чтения и записи в базу данных. Эта структура для программистов представлена в файле ibase.h (добавлены комментарии):
typedef struct {
short array_bound_lower;
/* нижняя граница массива или фрагмента */
short array_bound_upper;
/* верхняя граница массива или фрагмента */
} | SC_ARRAY_BOUND;
typedef struct {
unsigned char array_desc_dtype;
/* тип данных элементов */
char array_desc_scale;
/* масштаб для числовых типов */
unsigned short array_desc_length;
/* длина элемента массива в байтах */
char array_desc_field_name[32] ;
/* идентификатор столбца */
char array_desc_relation_name[32];
/* идентификатор таблицы */
short array_desc_dimensions;
/* количество размерностей */
short array_desc_flags;
/* 0=порядок по строкам, 1=порядок по столбцам */
ISC_ARRAY_BOUND array_desc_bounds[16];
/* верхняя и нижняя границы для размерности до 16 */
} ISC_ARRAY_DE SC;
Документ по InterBase 6 "API Guide" (Руководство no API), опубликованный Borland, содержит детальные инструкции по манипулированию массивами с помощью структур API.
Ограничения доступа динамического SQL
Следующий пример является простой демонстрацией того, как приложение DSQL может получить ограниченный доступ к фрагменту массива через хранимую процедуру:
create procedure getcharslice(
low_elem smallint, high_elem smallint)
returns (id integer, list varchar(50))
as
declare variable i smallint;
declare variable string varchar(10);
begin
for select a1.ID from ARRAYS a1 into :id do
begin
i= low_elem;
list = '' ;
while (i <= high_elem) do
begin
select a2.CHARARRAY[:i] from arrays a2
where a2.ID = :id
into : string;
list = list||string;
if (i < high_elem) then
list = list ||',';
i = i + 1;
end
suspend;
end
end
Пора дальшеПоследняя глава этой части книги описывает, как объединить тип данных и его дополнительные атрибуты в домен, который вы можете использовать для определения типов данных в столбцах различных таблиц.
ГЛАВА 13. Домены.
Домены в Firebird сродни концепции "типы данных, определенные пользователем". Хотя и невозможно создать новый тип данных, в домене вы можете "упаковать" набор атрибутов с одним из существующих типов данных, присвоить ему идентификатор и после этого использовать его как параметр типа данных для определения столбцов любой таблицы.
Определения доменов являются глобальными для базы данных - все столбцы в любой таблице, которые были определены с одним доменом, будут иметь совершенно идентичные атрибуты за исключением тех, которые были локально переопределены.
Как было отмечено, домены не могут быть подставлены вместо типов данных при определении аргументов и переменных в хранимых процедурах и триггерах.
! ! !
ПРИМЕЧАНИЕ. Замещение атрибутов домена на уровне столбца обсуждается позже в этой главе.
. ! .
Столбцы, основанные на определении домена, наследуют все атрибуты домена, которые могут быть:
* типом данных (обязательно);
* значением по умолчанию для INSERT;
* состоянием NULL;
* ограничениями CHECK;
* набором символов (только для символьных и BLOB столбцов);
* порядком сортировки (только для символьных столбцов).
- Delphi. Учимся на примерах - Сергей Парижский - Программирование
- Сделай видеоигру один и не свихнись - Слава Грис - Программирование / Руководства
- Психбольница в руках пациентов - Алан Купер - Программирование