12.07.2016 1 min to read

Передача BLOB через Database Link

Category : Статьи

Вопрос копирования данных BLOB через Database Link не является таким уж простым. К сожалению, в СУБД Oracle существуют существенные ограничения на работу с удаленной базой данных через внешнюю ссылку. Например, изменение значения данных типа LOB на удаленной БД не поддерживается. Выполнение следующих команд приведет к ошибке.

INSERT INTO table2@remote_db (blob_field) SELECT blob_field FROM table1;
UPDATE table2@remote_db SET blob_field = (SELECT blob_field FROM table1 WHERE ROWNUM = 1);
DELETE FROM table2@remote_db;

 

И даже попытка прямой выборки значения не сможет быть выполнена:

SELECT blob_field FROM table2@remote_db;

 

Получается, способа передачи LOB-значений через ссылку на внешнюю БД не существует? К счастью, способ есть! И не один.

Чтение данных BLOB через Database Link и изменение значений локально.

При перечисленных выше ограничениях, как ни странно, в обратном направлении работа с LOB возможна. Например, следующие команды будут выполнены без ошибок:

CREATE TABLE table2 AS SELECT * FROM table1@remote_db;
INSERT INTO table2 SELECT * FROM table1@remote_db;
UPDATE table2 SET blob_field = (SELECT blob_field FROM table1@remote_db);

 

Это дает возможность получить данные следующим способом (описание этого способа есть у Тома Кайта):

  1. Создается локальная временная таблица для загрузки LOB-данных.
  2. Через ссылку к удаленной БД выбирается LOB-значение и добавляется во временную таблицу.
  3. Работать с полученным значением во временной таблице можно без огрпничений.
CREATE GLOBAL TEMPORARY TABLE table_tmp (blob_field BLOB);
INSERT INTO table_tmp SELECT blob_field FROM table1@remote_db;
UPDATE table2 SET blob_field = (SELECT blob_field FROM table_tmp) WHERE id = :p_id;

 

Недостатки описанного способа: все операции необходимо делать на стороне БД, где данные будут записываться. Таким образом, со стороны БД, где хранятся исходные значения, нельзя напрямую вызвать процесс записи данных на удаленной БД. Для реализации старта процесса потребуется создание дополнительных триггеров и инициация событий, на которые будут срабатывать соответствующие триггера.

Изменение значения BLOB через Database Link средствами динамического SQL.

Все команды, которые не работают в обычном режиме, выполняются средствами динамического SQL.

DECLARE
    v_cur_id number;
    v_rows number;
BEGIN
    v_cur_id := DBMS_SQL.OPEN_CURSOR;

    DBMS_SQL.PARSE(v_cur_id, 'UPDATE table2@remote_db set blob_filed = (SELECT blob_filed from table1 WHERE id = :p_src) WHERE id = :p_dist', dbms_sql.native);
    DBMS_SQL.BIND_VARIABLE(v_cur_id, ':p_src', ...);
    DBMS_SQL.BIND_VARIABLE(v_cur_id, ':p_dist', ...);
    v_rows := DBMS_SQL.EXECUTE(v_cur_id);
    DBMS_SQL.CLOSE_CURSOR(v_cur_id);
END;

 

Недостатки второго способа: приведенный сценарий может быть выполнен только от имени непосредственной схемы-владельца внешней ссылки database link. Попытка создания соответствующей процедуры и выдача прав на ее выполнение другому пользователю приведет к ошибке во время вызова процедуры.

Tags: ,