Как вставить (файл) данные в Bytea столбец PostgreSQL?


38

Этот вопрос не о байтее v. Oid v. Blobs v. Крупных объектах и ​​т. Д.

У меня есть таблица, содержащая integerполе первичного ключа и byteaполе. Я хотел бы ввести данные в byteaполе. Предположительно, это может быть сделано одним из PL/языков, и я могу рассмотреть возможность сделать это PL/Pythonв будущем.

Поскольку я все еще тестирую и экспериментирую, я просто хотел бы вставить данные из файла (на сервере), используя «стандартные» операторы SQL. Я знаю, что только администраторы с правами на запись на сервере смогут вставлять данные так, как мне бы хотелось. Я не обеспокоен этим на данном этапе, поскольку пользователи не будут вставлять byteaданные в настоящее время. Я искал различные сайты StackExchange, архивы PostgreSQL и Интернет в целом, но не смог найти ответ.

Изменить: это обсуждение 2008 года подразумевает, что то, что я хочу сделать, невозможно. Как byteaтогда используются поля?

Изменить: этот похожий вопрос от 2005 года остается без ответа.

Решено: подробности, представленные здесь на psycopgсайте, послужили основой для решения, которое я написал на Python. Также возможно добавить двоичные данные в byteaстолбец, используя PL/Python. Я не знаю, возможно ли это с использованием «чистого» SQL.


1
Ссылка на документацию по psycopg не работает, и моя редакция была отклонена (!?). Вот текущее местоположение .
Арье Лейб Таурог

@AryehLeibTaurog: Спасибо. Я отклонил редактирование, потому что мне не было ясно, что ваш измененный текст был гиперссылкой. Если вы хотите внести изменения еще раз, я одобрю это.
SabreWolfy

@Andriy_M Почему вы думаете, что «это изменение отличается от первоначального замысла поста». (Правка, сделанная informatik01?)
miracle173

@ miracle173: Потому что у меня сложилось впечатление, что некоторые из предложенных тегов не имеют значения (ну, на самом деле, только один, на самом деле blob). Если это было ошибкой, я искренне извиняюсь.
Андрей М,

Ответы:


27

как суперпользователь:

create or replace function bytea_import(p_path text, p_result out bytea) 
                   language plpgsql as $$
declare
  l_oid oid;
begin
  select lo_import(p_path) into l_oid;
  select lo_get(l_oid) INTO p_result;
  perform lo_unlink(l_oid);
end;$$;

lo_get был введен в 9.4, поэтому для более старых версий вам понадобится:

create or replace function bytea_import(p_path text, p_result out bytea) 
                   language plpgsql as $$
declare
  l_oid oid;
  r record;
begin
  p_result := '';
  select lo_import(p_path) into l_oid;
  for r in ( select data 
             from pg_largeobject 
             where loid = l_oid 
             order by pageno ) loop
    p_result = p_result || r.data;
  end loop;
  perform lo_unlink(l_oid);
end;$$;

тогда:

insert into my_table(bytea_data) select bytea_import('/my/file.name');

Для обратного процесса, я не пробовал это , но если это сработает , lo_export будет все, что вам нужно
Джек Дуглас


15

Это решение не совсем эффективно с точки зрения времени выполнения, но тривиально просто по сравнению с созданием собственных заголовков для COPY BINARY. Кроме того, не требуется никаких библиотек или языков сценариев за пределами bash.

Сначала преобразуйте файл в hexdump, удвоив размер файла. xxd -pсближает нас, но добавляет некоторые раздражающие строки, о которых мы должны позаботиться:

xxd -p /path/file.bin | tr -d '\n' > /path/file.hex

Затем импортируйте данные в PostgreSQL как очень большое textполе. Этот тип содержит до одного ГБ на каждое значение поля, поэтому в большинстве случаев мы должны быть в порядке:

CREATE TABLE hexdump (hex text); COPY hexdump FROM '/path/file.hex';

Теперь, когда наши данные представляют собой безвозмездно большую шестнадцатеричную строку, мы используем PostgresQL, decodeчтобы получить их в виде bytea:

CREATE TABLE bindump AS SELECT decode(hex, 'hex') FROM hexdump;

Это решение приводит к удалению \ n символов из файла.
SabreWolfy

2
SabreWolfy: нет, это не так. Он tr -d '\n'работает на выходе xxd, который кодирует двоичное содержимое ввода в виде шестнадцатеричных символов ASCII (0-9 и af). xxd также происходит с выходными переводами строки через равные промежутки времени, чтобы сделать вывод понятным для человека, но в этом случае мы хотим, чтобы они были удалены. Перевод строки в исходных данных будет в шестнадцатеричной форме и останется неизменным.
товары на

5

Ответ с XXD хорош и для маленьких файлов, очень быстро. Ниже приведен пример сценария, который я использую.

xxd  -p /home/user/myimage.png | tr -d '\n' > /tmp/image.hex
echo "
    -- CREATE TABLE hexdump (hex text);
    DELETE FROM hexdump;
    COPY hexdump FROM '/tmp/image.hex';

    -- CREATE TABLE bindump (binarydump bytea);
    DELETE FROM bindump;

    INSERT INTO bindump (binarydump)  
    (SELECT decode(hex, 'hex') FROM hexdump limit 1);

    UPDATE users 
    SET image= 
    (
        SELECT decode(hex, 'hex') 
        FROM hexdump LIMIT 1
    )  
    WHERE id=15489 ;
    " | psql mydatabase

1

Используйте функцию Postgres COPY BINARY . Это в целом эквивалентно внешним таблицам Oracle .


Спасибо. Ссылка, которую вы указали, указывает, что данные должны быть в двоичном формате ASCII или PostgreSQL. Далее вниз по странице упоминается, что формат двоичной таблицы сначала создается с помощью команды COPY TO. Позволит ли любой из этих подходов вставить двоичный файл (PDF, документ, электронную таблицу) в byteaстолбец?
SabreWolfy

Документация PostgreSQL по COPY BINARY ( postgresql.org/docs/8.4/interactive/sql-copy.html ) указывает, что при вставке двоичных данных требуется специальный заголовок файла. Нужно ли создавать этот заголовок и добавлять его в двоичные данные? Это кажется довольно сложным для простого хранения строки двоичных данных.
SabreWolfy

Хм, теперь, когда вы упомянули об этом, я не уверен, я просто запомнил команду и предположил, что она это сделает. Возможно, PL / что-нибудь - единственный способ сделать это.
Гай
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.