double arrow

Нестандартное применение генераторов

Удаление генераторов.

Получение текущего значения генераторов.

Изменение значения генератора.

Значение генератора можно переустановить при помощи оператора DDL

SET GENERATOR generatorname TO value;

Однако вы не сможете использовать такое выражение в теле триггера или хранимой процедуры, т. к. там можно использовать только операторы DML (а не DDL).

Если вы хотите обнулить генератор, или присвоить ему определенное значение в теле хранимой процедуры, то вы можете это сделать, используя функцию GEN_ID: (В данном примере генератор NEWCLIENT увеличивается на свое же значение с отрицательным знаком.)

...
TEMPVAR = GEN_ID (NEWCLIENT, -GEN_ID (NEWCLIENT, 0);

...

Будьте внимательны при выполнении таких операций в многопользовательских средах. Приложения, процедуры и триггеры, которые в данный момент используют этот генератор, могут предполагать, что он не будет «обнулен». Обязательно проверяйте «обнуление» генератора на возникновение конфликтных ситуаций при работе 2-х и более пользователей.

Текущее значение генератора можно получить, вызвав функцию GEN_ID с нулевым увеличением значения генератора. Это можно сделать не только в триггере или хранимой процедуре, но и оператором SELECT

SELECT GEN_ID(NEWCLIENT, 0) FROM RDB$DATABASE;

Результатом выполнения запроса будет одна запись с одним полем, содержащим текущее значение генератора. Таблица RDB$DATABASES выбрана как содержащая в большинстве случаев одну запись, хотя использовать можно и любую другую таблицу.

При работе в многопользовательских средах будьте внимательны – в то время как вы получили «текущее» значение генератора, другое приложение может его изменить, и таким образом «текущее» значение окажется устаревшим. Тем более не рекомендуется использовать «текущее» значение генератора для его последующего изменения.

В языке DDL Borland Interbase нет оператора для удаления генератора. Неизвестно, чем это вызвано, но серьезной проблемы не представляет. В самом начале статьи было упомянуто, что запись о генераторе создается в таблице RDB$GENERATORS. Эту запись, безусловно, можно удалить. Однако место, распределенное на странице генераторов, освобождено не будет. Оно будет освобождено только после того, как вы сделаете вашей БД BACKUP/RESTORE.

Вы уже видели, что функцию GEN_ID можно использовать в операторе SELECT. Вот как можно получить количество записей, выбранных запросом:

SET GENERATOR MYGEN TO 0;

SELECT GEN_ID(MYGEN, 1), FIELD1, FIELD2, FIELD3, ...FROM MYTABLE;

Такой запрос вернет в качестве первого поля порядковый номер записи, и после выполнения запроса генератор MYGEN будет содержать количество возвращенных записей. Кроме этого, во время выполнения этого запроса любой другой пользователь этой же БД может получить текущее значение генератора MYGEN и узнать сколько записей уже выбрано запросом на текущий момент (нечто вроде ProgressBar, однако число записей все равно неизвестно до окончания выполнения запроса).

Функцию GEN_ID можно также использовать и как «выключатель» длительных запросов. Пример приведен для БД EMPLOYEE.GDB.

SET GENERATOR EMP_NO_GEN TO 0;

SELECT * FROM EMPLOYEE, EMPLOYEE, EMPLOYEE WHERE GEN_ID(EMP_NO_GEN, 0) = 0;

Фактически такой запрос означает – «выбирать записи пока значение генератора = 0». Как только другой пользователь или ваше приложение в другом коннекте выполнит операцию

SET GENERATOR EMP_NO_GEN TO 1;

запрос прекратится, т. к. условие WHERE станет равным FALSE.

Примечание: обязательно учитывайте буферизацию записей клиентской частью (gds32.dll) или сервером при выполнении подобных запросов. Например, приведенный выше запрос с проверкой генератора в where «выключится» не сразу, а через некоторое время.

Безусловно, в многопользовательской среде невозможно использовать в таких целях один и тот же генератор. Для решения этой проблемы можно завести глобальный генератор, который будет выдавать уникальные идентификаторы пользователям при коннекте, а клиентское приложение будет запоминать его номер и хранить на локальном компьютере для последующего использования. Логика работы может быть следующая:

Клиентское приложение при запуске определяет, есть ли для него (например в Registry или INI-файле) «именной» генератор.

Если нет, то оно операцией SELECT GEN_ID(GlobalGen, 1) FROM RDB$DATABASE получает идентификатор (например 150), создает на сервере собственный генератор операцией CREATE GENERATOR USER_N; (например USER150). После чего сохраняет имя этого генератора на локальном диске.

Если да, то приложение обнуляет «именной» генератор операцией SET GENERATOR ... TO 0; (в нашем примере SET GENERATOR USER150 TO 0;), и выдает запросы с использованием данного генератора.

При помощи генераторов можно также решить проблему с отсутствием временных таблиц в Borland Interbase. Вы создаете таблицу, например TEMP_TBL, и в качестве первого поля, входящего в первичный ключ, указываете поле типа INTEGER. Пользователь при соединении с сервером получает собственный идентификатор у некоторого общего генератора, и затем использует его при помещении записей в такую «временную» таблицу. В результате, даже если несколько пользователей будут работать с такой таблицей, они никогда не «пересекутся» по значению первого поля первичного ключа «временной» таблицы.


Сейчас читают про: