Найти идентификатор текущего задания/разрешить только одному заданию обновлять таблицу

У меня есть база данных "звезда". Один делает какую-то работу; у двух других есть задания, которые извлекают метаданные в свои справочные таблицы из первой базы данных. Я хочу запретить кому-либо обновлять, удалять или вставлять какие-либо записи в справочные таблицы в двух «рабах»; таблицы должны просто обновляться запланированным заданием.

В настоящее время я делаю это с помощью триггера, который проверяет, находится ли текущий SID в USER_SCHEDULER_RUNNING_JOBS с именем задания, которое, как я ожидаю, будет запущено. Я хотел бы изменить это, чтобы использовать JOB_ID задания, от которого я бегу.

Это моя текущая установка; предположим очень простую таблицу:

create table a ( b number );

и следующее задание:

begin
   dbms_scheduler.create_job(
          job_name        => 'test_job'
        , job_type        => 'PLSQL_BLOCK'
        , job_action      => 'begin
                                 merge into a a 
                                 using ( select 1 x from dual@db2 ) b 
                                    on (1 = 2)
                                  when not matched then 
                                       insert values (b.x);
                                 commit;
                              end;'
        , start_date      => sysdate
        , repeat_interval => 'FREQ = MINUTELY;'
        , enabled => true
          );
end;
/

Я использую этот триггер:

create or replace trigger tr_blah
before insert or update on a
declare
   l_ct number;
begin
   select count(*) into l_ct
     from user_scheduler_running_jobs
    where session_id = sys_context('USERENV','SID')
      and job_name = 'TEST_JOB'
          ;

   if l_ct = 0 then
      raise_application_error(-20000, 'FAIL');
   end if;
end;
/

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

SYS_CONTEXT() имеет параметры FG_JOB_ID и BG_JOB_ID. Их описание, особенно описание FG_JOB_ID, подразумевает, что они могут быть JOB_ID текущего задания. Изменение триггера на следующее (я пробовал оба):

create or replace trigger tr_a
before insert or update or delete on a
declare
   l_ct number;
begin
      raise_application_error(-20000, sys_context('USER_ENV', 'BG_JOB_ID'));
end;
/

Результаты в следующем

ORA-20000: 
ORA-06512: at "REF.TR_A", line 4
ORA-04088: error during execution of trigger 'REF.TR_A'
ORA-06512: at line 2

Это означает, что и FG_JOB_ID, и BG_JOB_ID равны нулю. Есть ли метод определения идентификатора задания, работающего в текущем сеансе, чтобы мне не нужно было каждый раз использовать JOB_NAME?


person Ben    schedule 05.11.2013    source источник


Ответы (1)


Наиболее элегантным решением является использование разных пользователей базы данных. Убедитесь, что задание выполняется под пользователем, у которого есть разрешения на обновление, вставку и удаление таблиц (возможно, владелец схемы таблиц). Не давайте эти гранты другим пользователям.

Не нужно возиться с триггерами и прочим.

person Rene    schedule 05.11.2013
comment
Это более элегантное решение; это не останавливает несчастные случаи, хотя ... Я пытаюсь запретить, а не запутать. (мне тоже интересен ответ - можно ли узнать id работы) - person Ben; 05.11.2013
comment
Разные пользователи с разными паролями и разными правами доступа. Это ни в коем случае не форма запутывания. - person Rene; 06.11.2013