|
|
Эта глава описывает массивы типов данных и как работать с ними используя API функции. Она показывает как установить дескриптор массива определяющий однозначно массив или массив подмножеств для выборки или для записи, и как использовать две API функции которые управляют доступом к массивам. Следующая таблица содержит все API функции для работы с массивами. Первые функции показаны те которые могут быть использованы для инициализации дескриптора массива, а другие для доступа массиву данным.
7.1.Введение в массивыInterBase поддерживает массивы большинства типов данных. Использование массива позволяет множественным элементам данных быть сохраненным в одном столбце. InterBase может обращаться с массивом как отдельным модулем, или как рядом отдельных модулей, называемых секторами. Использование массива уместно когда: Элементы данных естественно образуют набор того же самого типа данных. Полный набор элементов данных в отдельном)столбце базы данных должен быть представлен и управляться как модуль, в противоположность сохранению каждого элемента в отдельном столбце. Каждый элемент должен также быть идентифицирован и иметь индивидуальный доступ. Элементы данных в массиве называются элементами массива. Массив может содержать элементы любого типа данных InterBase кроме Blob, а также не может быть массив массивов. Все элементы определенного массива имеют тот же самый тип данных. InterBase поддерживает многомерные массивы, массивы с от 1 до 16 размерностей. Многомерные массивы хранятся в строке - в основном порядок). Размерности Массива имеют определенный диапазон верхних и нижних границ, называемых нижними индексами. Нижние индексы массива определяются, когда столбец массива создается. 7.2.Хранение массивов БДIB не хранит непосредственно массив данных в поле записи таблицы. Там она хранит ID массива. ID массива есть уникальное числовое значение которое ссылается на массив данных, который хранится в другом месте БД. 7.2.1.Дескрипторы массиваДескриптор массива описывает как массив или подмножество массива выбираться или записываться в ISC_ARRAY_DESC структуру. ISC_ARRAY_DESC определена в заголовочном файле ibase.h в таком виде: typedef struct { unsigned char array_desc_dtype; /* Datatype */ char array_desc_scale; /* Scale for numeric datatypes */ unsigned short array_desc_length; /* Length in bytes of each array element */ char array_desc_field_name [32]; /* Column name */ char array_desc_relation_name [32]; /* Table name */ short array_desc_dimensions; /* Number of array dimensions */ short array_desc_flags; /* Specifies whether array is to be accessed in row-major or column-major order */ ISC_ARRAY_BOUND array_desc_bounds [16]; /* Lower and upper bounds for each dimension */ } ISC_ARRAY_DESC; ISC_ARRAY_BOUND определен как: typedef struct { short array_bound_lower; /* lower bound */ short array_bound_upper; /* upper bound */ } ISC_ARRAY_BOUND; Дескриптор массива содержит 16 ISC_ARRAY_BOUND структур, одну для каждой возможной размерности. Массив с n размерностями устанавливает верхние и нижние границы для первых n ISC_ARRAY_BOUND структур. Число фактических размерностей массива определено в array_desc_dimensions поле дескриптора массива. Когда Вы выбираете данные из массива, Вы применяете Дескриптор массива определяющий сектор массива (полный массив или подмножество смежных элементов массива) для выборки. Точно так же, когда Вы записываете данные в массив, Вы применяете дескриптор массива определяющий сектор массива который будет записан . 7.3.Инициализация дескриптора массиваСуществуют 4 способа для инициализации дескриптора массива: - Вызовите isc_array_lookup_desc(), который найдет ( в системной таблице метаданных) и сохранит в дескрипторе массива тип данных, длину, масштаб и размерности для определенного для массива столбца в определенной таблице. Эта функция также сохранит название таблицы и столбца в дескрипторе, и инициализирует его array_desc_flags поле показывающее какой массив доступен в первой строке. К примеру: isc_array_lookup_desc( status_vector, &db_handle, /* Set by isc_attach_database() */ &tr_handle, /* Set by isc_start_transaction() */ "PROJ_DEPT_BUDGET",/* table name */ "QUART_HEAD_CNT",/* array column name */ &desc /* Инициализируемый дескриптор */ ); - Вызовите isc_array_lookup_bounds(), который найдет и выполнит тот же самый вызов isc_array_lookup_desc (), за исключением того, что функция isc_array_lookup_bounds () также выбирает и сохраняет в Дескрипторе массива верхние и нижние границы каждой размерности - Вызовите isc_array_set_desc(), которая инициализирует дескриптор параметрами, быстрее нежели она стала бы обращаться к метаданным для инициализации. Например: short dtype = SQL_TEXT; short len = 8; short numdims = 2; isc_array_set_desc( status_vector, "TABLE1", /* table name */ "CHAR_ARRAY", /* array column name */ &dtype, /* datatype of elements */ &len, /* length of each element */ &numdims, /* number of array dimensions */ &desc /* descriptor to be filled in */ ); - Установите дескриптор полей на прямую. Например, установка поля array_desc_dimensions в дескрипторе desc происходит так: desc.array_desc_dimensions = 2; 7.3.1.Доступ к массиву данныхInterbase поддерживает следующие операции над массивом данных: - Чтение из массива или сектора массива - Запись в массив: Включение нового массива в строку вставляемую в таблицу. Замена массива ссылающегося на столбец массива строкой с новым массивом Обновление массива ссылающегося на столбец массива строкой с модифицированными данными и сектора с данными - Удаление массива DSQL API функции и структуры данных XSQLDADSQL функции API и структуры данных XSQLDA необходимы, чтобы выполнить SELECT, INSERT, и инструкции UPDATE. Следующие секции включают описания DSQL, программные методы, нужные для выполнения этих инструкций Примечание: Следующие операции над массивом не поддерживаются: - Ссылка на размеры массива динамически в DSQL - Установка элемента массива в NULL - Использование аггрегативных функций, таких как min(), max(), с массивами. - Ссылка на массивы в GROUP BY - Создание представлений которые производят выборку из секторов массива 7.4.Чтение данных из массиваЕсть 7 шагов для чтения данных из массива или сектора массива:
7.4.1.Создание строки SELECTchar *sel_str = "SELECT DEPT_NO, QUART_HEAD_CNT FROM PROJ_DEPT_BUDGET \ WHERE year = 1994 AND PROJ_ID =’VBASE’"; 7.4.2.Подготовка XSQLDA ля выводаXSQLDA *out_sqlda; out_sqlda = (XSQLDA*)malloc(XSQLDA_LENGTH(2)); out_sqlda->version = SQLDA_VERSION1; out_sqlda->sqln = 2; 7.4.3.Подготовка SELECT инструкции к выполнениюisc_stmt_handle stmt; /* Declare a statement handle. */ stmt = NULL; /* Set handle to NULL before allocation. */ isc_dsql_allocate_statement(status_vector,&db_handle, &stmt); isc_dsql_prepare( status_vector, &trans, /* Set by previous isc_start_transaction() call. */ &stmt, /* Statement handle set by this function call. */ 0, /* Specifies statement string is null-terminated. */ sel_str, /* Statement string. */ 1, /* XSQLDA version number. */ out_sqlda /* XSQLDA for storing column data. */ ); Устанавливаем XSQLVAR структуру дл я каждого столбца. Для столбцов чьи типы известны во время компиляции - Определяем тип столбца (если он не был установлен isc_dsql_prepare()) - Указатель sqldata связывает с локальными переменными Для столбцов чьи типы неизвестны во время компиляции - Приводим типы элементов(необязательно). Например, SQL_VARYING к SQL_TEXT. - Динамически выделяем память для локального хранения данных, и указатель на нее присваиваем sqldata Не забываем кому нужно про NULL индикатор Поиск данных для массивов (и Blob) столбцов отличаются от других типов столбцов, так что поля
XSQLVAR должны быть установлены по-другому. Для
не массива (и не BLOB) столбцов, isc_dsql_pr Пример внизу: ISC_QUAD array_id = 0L; char dept_no[6]; short flag0, flag1; out_sqlda->sqlvar[0].sqldata = (char *) dept_no; out_sqlda->sqlvar[0].sqltype = SQL_TEXT + 1; out_sqlda->sqlvar[0].sqlind = &flag0; out_sqlda->sqlvar[1].sqldata = (char *) &array_id; out_sqlda->sqlvar[1].sqltype = SQL_ARRAY + 1; out_sqlda->sqlvar[1].sqlind =&flag1; isc_dsql_execute( status_vector, &trans, /* set by previous isc_start_transaction() call */ &stmt, /* set above by isc_dsql_prepare() */ 1, /* XSQLDA version number */ NULL /* NULL since stmt doesn’t have input values */ ); 1. Создаем дескриптор массива ISC_ARRAY_DESC desc; 2. И заполняем дескриптор массива как было описано выше isc_array_lookup_bounds( status_vector, &db_handle, &trans, "PROJ_DEPT_BUDGET",/* table name */ "QUART_HEAD_CNT",/* array column name */ &desc); Предположим столбец массива, QUART_HEAD_CNT, - одномерный массив, состоящий из
четырех элементов, и он был объявлен нижний индекс 1 и верхним 4, когда это был создан. Тогда
после вышеупомянутого запроса к isc_array_lookup_bounds (), поля Дескриптора массива для границ
будут содержать следующую информацию: desc.array_desc_bounds[0].array_bound_lower == 1 desc.array_desc_bounds[0].array_bound_upper== 4 Если Вы хотите читать только сектор массива, то измените
верхние или нижние границы соответственно. Например, если Вы только хотите
читать первые два элемента массива, измените верхнюю границу к значению 2, как в: desc.array_desc_bounds[0].array_bound_upper= 2 ISC_STATUS fetch_stat; long SQLCODE; . . . while ((fetch_stat = j isc_dsql_fetch(status_vector, &stmt, 1, out_sqlda)) == 0) { /* Read and process the array data */ } if (fetch_stat != 100L) { /* isc_dsql_fetch returns 100 if no more rows remain to be retrieved */ SQLCODE = isc_sqlcode(status_vector); isc_print_sqlerror(SQLCODE, status_vector); return(1); } Чтение и обработка массива или массива сектора данных: 1. Создаем буфер для хранения читаемых данных. Сделайте его достаточного размера для хранения всех
элементов читаемого сектора. Например, следующий код делает объявление буфера массива
для хранения 4 long элементов. longhcnt[4]; 2. Объявляем short переменную для определения размера буфера массива shortlen; 3. Устанавливаем переменную в длину буфера: len = sizeof(hcnt); 4. Читаем массив или массив сектора данных в буфер вызвав isc_array_get_slice().Обрабатываем прочитанные данные. В следующем примере массив читается в
hcnt буфер массива, и обрабатывается. isc_array_get_slice( status_vector, &db_handle,/* set by isc_attach_database()*/ &trans, /* set by isc_start_transaction() */ &array_id, /* array ID put into out_sqlda by isc_dsql_fetch()*/ &desc, /* array descriptor specifying slice to be read */ (void *) hcnt,/* buffer into which data will be read */ (long *) &len/* length of buffer */ ); if (status_vector[0] == 1 && status_vector[1]) { isc_print_status(status_vector); return(1); } /* Make dept_no a null-terminated string */ dept_no[out_sqlda->sqlvar[0].sqllen] = ’\0’; printf("Department #: %s\n\n", dept_no); printf("\tCurrent head counts: %ld %ld %ld %ld\n", hcnt[0], hcnt[1], hcnt[2], hcnt[3]); Isc_array_put_slice() вызывается для записи данных в массив или
массив секторов Следующие шаги требуются для вставки, замены, или обновления массива данных Подготовка дескриптора с информацией описывающей массив (или сектор) для записи Подготовка буфера массива с данными для записи. Подготовка соответствующей DSQL инструкции. Вызовите isc_array_put_slice() для создания нового массива, и для записи данных из буфера массива в массив или сектор массива Свяжите новый массив со столбцом массива, установив его значение к ID массива 1. Создайте дескриптор массива: ISC_ARRAY_DESC desc; 2. Заполните дескриптор информацией Заполните дескриптор информацией
относительно столбца массива, куда данные будут записаны. Делайте это или, вызывая одну из функций isc_array_lookup_bounds (), isc_array_lookup_desc (), или isc_array_set_desc (), или, непосредственно заполняя Дескриптор. isc_array_lookup_bounds( status_vector, db_handle, &trans, "PROJ_DEPT_BUDGET",/* table name */ "QUART_HEAD_CNT",/* array column name */ &desc); long hcnt[4]; short len; len = sizeof(hcnt); заполняем буфер данными hcnt[0] = 4; hcnt[1] = 5; hcnt[2] = 6; hcnt[3] = 6; char *upd_str = "UPDATE PROJ_DEPT_BUDGET SET QUART_HEAD_CNT = ? WHERE \ YEAR = 1994 AND PROJ_ID ="MKTPR" AND DEPT_NO = ?"; XSQLDA *in_sqlda; in_sqlda = (XSQLDA*)malloc(XSQLDA_LENGTH(2)); in_sqlda->version = SQLDA_VERSION1; in_sqlda->sqln = 2; #define NUMLEN 4 char dept_no[NUMLEN + 1]; ISC_QUAD array_id; in_sqlda->sqlvar[0].sqldata = &array_id; in_sqlda->sqlvar[0].sqltype = SQL_ARRAY + 1; in_sqlda->sqlvar[0].sqllen = sizeof(ISC_QUAD); in_sqlda->sqlvar[1].sqldata = dept_no; in_sqlda->sqlvar[1].sqltype = SQL_TEXT; in_sqlda->sqlvar[1].sqllen = 4; 1. Объявляем ID массива ISC_QUAD array_id; /* Declare an array ID. */ 2. Инициализируем его array_id = NULL;/* Set handle to NULL before using it */ 3. Вызываем isc_array_put_slice(). isc_array_put_slice( status_vector, &db_handle, &trans, &array_id,/* array ID (NULL, or existing array’s array ID) */ &desc, /* array descriptor describing where to write data */ hcnt, /* array buffer containing data to write to array */ &len /* length of array buffer */ ); isc_dsql_execute_immediate( status_vector, &db_handle, &trans, 0, /* indicates string to execute is null-terminated */ upd_str, /* UPDATE statement string to be executed */ 1, /* XSQLDA version number */ in_sqlda /* XSQLDA supplying parameters to UPDATE statement */ ); Существует три способа удаления Удалите строку содержащую массив обычной инструкцией DELETE Замените массив други, как описано выше. Если массив столбец содержит ID массива, и вы модифицируете столбец ссылкой на другой массив, то массив со старым ID будет удален во время следующей сборки “мусора”. Сбросьте в NULL столбец ссылающийся на массив. Например, используя DSQL инструкцию: "UPDATE JOB SET
LANGUAGE_REQ = NULL \ WHERE JOB_CODE = "SA12" ANDJOB_GRADE = 10" И массив, ссылка на который стала NULL, будет удален при следующей сборке “мусора” |
Дизайн: Piton Alien |