Эмуляция Oracle Global Temporary Table

Зачем эмулировать Global Temporary Table, если этот механизм и так встроен в базу данных Oracle? Действительно, незачем, если ваше приложение полностью построено с применением только одного клиента, который может быть написан на чем угодно. Однако может возникнуть ситуация, в которой ваше основное приложение использует результаты вычислений другого приложения, которое записывает выходные данные в некоторую таблицу, данные из которой и должно считать основное приложение. Например, отдельное не визуальное приложение на Java производит некоторые сложные вычисления, результаты которого необходимо отобразить пользователю в визуальном приложении на Oracle Forms. Причем эти данные являются временными, т.е. необходимыми только один раз для визуального отображения пользователю. Налицо необходимость организации взаимодействия между разными приложениями, работающими в разных сессиях.

Если бы сессия была одна, то для отображения таких временных данных прекрасно подошла бы Global Temporary Table, данные в которой живут максимум в течение текущей сессии Oracle. В случаях разных приложений с разными сессиями такой вариант не подойдет, следовательно, нам необходимо эмулировать Oracle Global Temporary Table для разных сессий. При такой эмуляции, необходимо сохранить нормальную многопользовательскую поддержку обработки данных в такой таблице.

Прежде всего необходимо заметить, что данные в Oracle Global Temporary Table привязаны не к конкретному пользователю, а к его сессии. Иными словами, пользователь может запустить две копии своего визуального приложения с одним и тем же логином и обрабатывать одни и те же данные. При этом для каждой сессии Global Temporary Table будет содержать свой уникальный набор данных.

Для эмуляции подобного поведения в случае разных приложений в разных сессиях в необходимо создать обычную таблицу, не Global Temporary, в которой будут требуемые вам поля и будет добавлено поле SESS varchar2(256), которое будет служить для хранения идентификатора или кода сессии пользователя основного приложения.

Код сессии можно формировать по разному, например, использовать для этого следующую функцию:

FUNCTION UNIQUE_SESSION_NAME RETURN VARCHAR2
IS
  lsUSER VARCHAR2(256);
  lnSID NUMBER;
  lnSERIAL NUMBER;
BEGIN
 
  SELECT USERNAME,SID,SERIAL#
    INTO lsUSER,lnSID,lnSERIAL
    FROM V$SESSION
   WHERE AUDSID = USERENV('sessionid');
     
  RETURN lsUSER||'$'||lnSID||'$'||lnSERIAL;
 
END UNIQUE_SESSION_NAME;

Сценарий дальнейшей работы может быть примерно следующим:Ваше основное визуальное приложение отправляет запрос на вычисление данных другому расчетному приложению, в качестве одного из параметров такого запроса выступает код сессии пользователя, сформированный функцией UNIQUE_SESSION_NAME. Прием и передачу таких запросов разными приложениями можно организовать при помощи пакета DBMS_PIPE. Расчетное приложение, приняв запрос, выполняет требуемые вычисления и записывает результаты в таблицу. Код сессии при этом записывается в каждую строку таблицы результатов. Основное приложение получает подтверждение о выполнении запроса и показывает вычисленные данные из таблицы результатов, фильтруя их по коду сессии пользователя.Что мы забыли сделать в этом алгоритме, так это позаботиться об очистке таблицы от старых данных этой же сессии, а так же от данных сессий, которые уже не подключены к базе данных. Для выполнения такой очистки можно использовать такую функцию:

PROCEDURE DELETE_DATA(psSESS IN VARCHAR2)
IS
BEGIN
 
  DELETE RESULT_TABLE
   WHERE SESS = psSESS
      OR SESS NOT IN (SELECT USERNAME||'$'||SID||'$'||SERIAL#
                        FROM V$SESSION
                     );
 
END DELETE_DATA;

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

Ссылка на основную публикацию