PostgreSQL COPY FROM PROGRAM: команда на сервере

Категория: Postgresql · Язык: SQL · Обновлено:

COPY ... FROM PROGRAM запускает shell-команду на сервере базы и читает её stdout как входные данные. Так можно импортировать сжатый файл или поток из другой утилиты без промежуточной распаковки. Команда выполняется от имени ОС-пользователя PostgreSQL, поэтому доступ к ней должен быть только у администратора.

Импортировать gzip-файл с сервера

SQL
CREATE TABLE events (
    id integer PRIMARY KEY,
    payload text NOT NULL
);

COPY events (id, payload)
FROM PROGRAM 'gzip -dc /var/backups/events.csv.gz'
WITH (FORMAT csv, HEADER true);

SELECT count(*) FROM events;

gzip -dc печатает распакованный CSV в stdout, а COPY разбирает его по формату csv с заголовком. Путь и команда должны быть фиксированными и доверенными: не подставляйте туда имя файла из пользовательского запроса. Если команда завершится с ненулевым кодом, COPY отменится, и строки не попадут в таблицу.

Для выполнения нужен суперпользователь или роль с правом pg_execute_server_program (PostgreSQL 11+), а также INSERT на таблицу. На управляемых сервисах вроде RDS эта возможность часто отключена. Проверьте права заранее: \du покажет роль, а SHOW is_superuser — текущий статус.

Обратная операция COPY ... TO PROGRAM отправляет данные в команду, например в gzip или ssh. Она так же опасна: команда получает доступ к данным и выполняется с правами сервера. Не используйте PROGRAM в веб-приложении и не объединяйте с динамическим SQL.

Безопасная альтернатива для приложения — COPY ... FROM STDIN с потоком из клиента или psql-команда \copy, которая читает файл на машине клиента. Для больших загрузок отдавайте файл в приложение и передавайте его драйвером, а не просите сервер запускать shell.

Проверяйте кодировку, разделители и NULL-маркеры до импорта. COPY FROM вызывает триггеры и проверяет ограничения таблицы, но не выполняет правила CREATE RULE. Если на таблице висят тяжёлые триггеры, импорт большого файла может быть заметно медленнее обычной вставки.

Документация: COPY, pg_execute_server_program.