F.46. pgpro_bfile — составной тип для доступа к внешнему файлу #

Расширение pgpro_bfile добавляет составной тип bfile, который реализует метод Oracle для доступа к внешнему файлу.

F.46.1. Структуры данных #

Тип bfile содержит два поля:

  • dir_id — идентификатор каталога в таблице bfile_directories

  • file_name — имя внешнего файла

Информация о каталогах хранится в таблице bfile_directories, которая состоит из следующих столбцов:

  • dir_id — уникальный идентификатор каталога типа int32.

  • dir_alias — уникальный псевдоним каталога.

  • dir_path — путь к каталогу.

Хотя наличие двух уникальных идентификаторов dir_id и dir_alias является избыточным, работа с dir_alias удобнее для пользователя, мигрирующего с Oracle, особенно для понимания семантики команд, а для хранения dir_id лучше использовать тип bfile, поскольку для него требуется меньше места в хранилище и он обеспечивает более быстрый поиск.

Информация о правах доступа к каталогам хранится в таблице bfile_directory_roles, которая состоит из следующих столбцов:

  • dr_dir_id — идентификатор каталога типа int32, то есть внешняя ссылка на столбец dir_id в таблице bfile_directories.

  • dr_role_id — идентификатор пользователя или роли, имеющей права доступа к каталогу.

  • dr_rights — битовый массив прав доступа к каталогу (1 означает доступ для чтения, 2 — доступ для записи). Выбор битового массива предусматривает возможность предоставления новых прав доступа, например необходимость в отдельном праве на удаление.

F.46.2. Функции #

Функции для работы с каталогами и управления правами доступа к каталогам реализованы на языке PL/PgSQL, а функции для работы со значениями bfile реализованы на языке C для повышения эффективности.

Таблица F.36. Функции для работы с каталогами

Функция

Описание

bfile_directory_create (a_dir_alias text, a_dir_path text) returns (int)

Создаёт каталог для заданных псевдонима и пути и возвращает идентификатор созданного каталога. Для вызова этой функции требуются права суперпользователя.

bfile_directory_delete (a_dir_alias text) returns (void)

Удаляет каталог с заданным псевдонимом. Для вызова этой функции требуются права суперпользователя.

bfile_directory_rename (a_dir_alias text, a_new_dir_alias text) returns (void)

Изменяет псевдоним каталога. Для вызова этой функции требуются права суперпользователя.

bfile_directory_set_path (a_dir_alias text, a_dir_path text) returns (void)

Изменяет путь к каталогу с заданным псевдонимом. Для вызова этой функции требуются права суперпользователя.

bfile_directory_get_path_by_alias (a_dir_alias text) returns (text)

Возвращает путь к каталогу с заданным псевдонимом.

bfile_directory_get_path_by_id (a_dir_id int) returns (text)

Возвращает путь к каталогу с заданным идентификатором.

bfile_directory_get_alias_by_id (a_dir_id int) returns (text)

Возвращает псевдоним каталога с заданным идентификатором.

bfile_directory_get_id_by_alias (a_dir_alias text) returns (int)

Возвращает идентификатор каталога с заданным псевдонимом.


Таблица F.37. Функции предоставления и отзыва прав доступа к каталогам

Функция

Описание

bfile_grant_directory (a_dir_alias text, a_role_name text, a_access_mask int) returns (void)

Предоставляет права доступа к каталогу a_dir_alias пользователю/роли a_role_name. В параметре a_access_mask указывается, какое право доступа предоставить (1 — чтение, 2 — запись, 3 — чтение и запись). Для вызова этой функции требуются права суперпользователя.

bfile_revoke_directory (a_dir_alias text, a_role_name text, a_access_mask int) returns (void)

Отзывает права доступа к каталогу a_dir_alias у пользователя/роли a_role_name. В параметре a_access_mask указывается, какое право доступа отозвать (1 — чтение, 2 — запись, 3 — чтение и запись). Для вызова этой функции требуются права суперпользователя.

bfile_cleanup_directory_roles () returns (void)

Удаляет из таблицы bfile_directory_roles информацию о правах доступа к каталогам для удалённых пользователей/ролей. Для вызова этой функции требуются права суперпользователя.


Таблица F.38. Функции для работы со значениями bfile

Функция

Описание

bfile_make (a_dir_alias text, a_file_name text) returns (bfile)

Возвращает структуру bfile для заданного псевдонима каталога и имени файла.

bfile_make_dir_id (a_dir_id int, a_file_name text) returns (bfile)

Возвращает структуру bfile для заданного идентификатора каталога и имени файла.

bfile_open (a_bfile bfile[, a_access_mask int]) returns (int)

Открывает файл для заданного a_bfile и возвращает его дескриптор. Параметр a_access_mask определяет режим доступа к файлу (1 — чтение, 2 — запись, 3 — чтение и запись), значение по умолчанию — 1.

bfile_close (a_handler int) returns (void)

Закрывает файл для заданного дескриптора, возвращаемого функцией bfile_open.

bfile_close_all () returns (int)

Закрывает все файлы, которые были открыты ранее функцией bfile_open. Возвращает количество закрытых файлов.

bfile_length (a_handler int) returns (bigint)

Возвращает длину открытого файла с заданным дескриптором.

bfile_read (a_handler int[, a_offset bigint, a_length bigint]) returns (bytea)

Считывает a_length байт со смещением a_offset от начала файла из открытого файла с дескриптором a_handler и возвращает прочитанные байты. По умолчанию параметр a_length равен -1, что означает чтение до конца файла, а параметр a_offset равен 0, что означает чтение с начала файла.

bfile_write (a_handler int, a_buffer bytea[, a_offset bigint]) returns (void)

Записывает буфер, заданный в a_buffer, в открытый файл, имеющий заданный дескриптор a_handler, с заданным смещением a_offset от начала файла. По умолчанию параметр a_offset равен -1, что означает запись с конца файла.

bfile_fileexists (a_bfile bfile) returns (boolean)

Возвращает true, если файл, соответствующий значению a_bfile, можно использовать. Функция проверяет, что файл открывается без ошибок.

bfile_length_direct (a_bfile bfile) returns (bigint)

Возвращает длину файла для заданного значения a_bfile.

bfile_read_direct (a_bfile bfile[, a_offset bigint, a_length bigint]) returns (bytea)

Для заданного значения a_bfile считывает a_length байт со смещением a_offset от начала файла и возвращает прочитанные байты. По умолчанию параметр a_length равен -1, что означает чтение до конца файла, а параметр a_offset равен 0, что означает чтение с начала файла.

bfile_write_direct (a_bfile bfile, a_buffer bytea) returns (void)

Для заданного значения a_bfile записывает заданный буфер a_buffer в новый файл. Требуется доступ для записи в каталог a_bfile.

bfile_delete (a_bfile bfile) returns (void)

Удаляет файл для заданного значения a_bfile. Требуется доступ для записи в каталог a_bfile.

bfile_compare (a_bfile_1 bfile, a_bfile_2 bfile[, a_amount bigint, a_offset_1 bigint, a_offset_2 bigint]) returns (int)

Когда аргументы a_amount, a_offset_1 и a_offset_2 не указаны, если размеры a_bfile_1 и a_bfile_2 различаются, возвращает -1, если размер a_bfile_1 меньше размера a_bfile_2, и 1 в противном случае. Если файлы одинакового размера, функция выполняет побайтовое сравнение данных файла и возвращает следующие значения: 0, если данные равны; -1, если данных в a_bfile_1 меньше, чем в a_bfile_2; 1, если данных в a_bfile_1 больше, чем в a_bfile_2. Параметр a_amount указывает количество байтов для сравнения, а a_offset_1 и a_offset_2 определяют смещения для начала сравнения.


F.46.3. Пример #

В следующем примере показано использование типа bfile.

Скрипт будет запускаться в файловой системе сервера. Но сначала создайте каталог для хранения данных bfile:

mkdir "/tmp/bfiles"

Теперь для запуска следующего скрипта будет использоваться psql:

-- Создание расширения pgpro_bfile:
CREATE EXTENSION pgpro_bfile;

-- Создание каталога в базе данных для хранения bfile:
SELECT bfile_directory_create('BFILE_DATA', '/tmp/bfiles');

-- Создание файла bfile.data в файловой системе и добавление в него значения '0123456789':
SELECT bfile_write_direct(bfile_make('BFILE_DATA', 'bfile.data'), '0123456789');

-- Создание таблицы bfile и добавление в неё одной записи, ссылающейся на этот файл:
CREATE TABLE bfile_table(id int, bf bfile);
INSERT INTO bfile_table VALUES (1, bfile_make('BFILE_DATA', 'bfile.data'));

-- Создание пользователя для запуска скрипта:
CREATE USER bf_test_user;

-- Предоставление пользователю bf_test_user права чтения и записи в файл BFILE_DATA:
SELECT bfile_grant_directory('BFILE_DATA', 'bf_test_user', 3);

-- Предоставление пользователю bf_test_user прав на таблицу bfile_table:
GRANT ALL ON bfile_table TO bf_test_user;

-- Авторизация bf_test_user:
SET SESSION AUTHORIZATION bf_test_user;

DO $$
DECLARE
  v_bfile bfile;
  v_buffer bytea;
  v_length bigint;
  v_handler int;
BEGIN
  -- Открытие файла для чтения и записи:
  SELECT bfile_open(bf, 3) INTO v_handler FROM bfile_table WHERE id = 1;

  -- Эта строка символов будет записана в конец файла:
  PERFORM bfile_write(v_handler, '_suffix');
  -- Эта строка символов будет записана с позиции 0 и заменит '0123456':
  PERFORM bfile_write(v_handler, 'prefix_', 0);

  -- Считывание строки символов из файла в буфер и вывод её длины и содержимого:
  v_buffer = bfile_read(v_handler);
  RAISE NOTICE 'Buffer length: %', length(v_buffer);
  RAISE NOTICE 'Buffer content: %', encode(v_buffer, 'escape');

  -- Получение и вывод длины файла:
  v_length = bfile_length(v_handler);
  RAISE NOTICE 'BFILE length: %', v_length;

  -- Закрытие bfile:
  PERFORM bfile_close(v_handler);
END $$;

-- Проверка содержимого таблицы:
SELECT encode(b, 'escape'), length(b) from (SELECT bfile_read_direct(bf) b FROM bfile_table) x;

-- Удаление таблицы, пользователя и расширения pgpro_bfile:
RESET SESSION AUTHORIZATION;
DROP TABLE bfile_table;
DROP USER bf_test_user;
DROP EXTENSION pgpro_bfile;

Скрипт выдаёт следующий результат:

 CREATE EXTENSION
 bfile_directory_create
------------------------
                      1
(1 row)

 bfile_write_direct
--------------------

(1 row)

CREATE TABLE
INSERT 0 1
CREATE ROLE
 bfile_grant_directory
-----------------------

(1 row)

GRANT
SET
NOTICE:  Buffer length: 17
NOTICE:  Buffer content: prefix_789_suffix
NOTICE:  BFILE length: 17
DO
      encode       | length
-------------------+--------
 prefix_789_suffix |     17
(1 row)

RESET
DROP TABLE
DROP ROLE
DROP EXTENSION