it-swarm.it

Come inserire i dati (file) in una colonna bytea di PostgreSQL?

Questa domanda non riguarda bytea v. Oid v. Blobs v. Oggetti di grandi dimensioni, ecc.

Ho una tabella contenente una chiave primaria integer field e un bytea field. Vorrei inserire i dati nel campo bytea. Questo, presumibilmente, può essere fatto da uno dei PL/ lingue, e potrei cercare di farlo con PL/Python nel futuro.

Dato che sto ancora testando e sperimentando, vorrei semplicemente inserire dati da un file (sul server) usando istruzioni SQL "standard". Sono consapevole che solo gli amministratori con autorizzazione di scrittura sul server sarebbero in grado di inserire i dati nel modo in cui vorrei. Non sono preoccupato per questo in questa fase poiché gli utenti non inseriscono attualmente bytea dati. Ho cercato i vari siti StackExchange, gli archivi PostgreSQL e Internet in generale, ma non sono riuscito a trovare una risposta.

Modifica: Questa discussione del 2008 implica che ciò che voglio fare non è possibile. Come vengono utilizzati i campi bytea?

Modifica: Questa una domanda simile del 2005 rimane senza risposta.

Risolto: I dettagli forniti qui sul sito Web psycopg hanno fornito le basi per una soluzione che ho scritto in Python. Potrebbe anche essere possibile inserire dati binari in una colonna bytea usando PL/Python. Non so se questo sia possibile usando SQL "puro".

40
SabreWolfy

come superutente:

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 è stato introdotto in 9.4, quindi per le versioni precedenti avresti bisogno di:

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;$$;

poi:

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

Usa pg_read_file('location_of file')::bytea.

Per esempio,

create table test(id int, image bytea);
insert into test values (1, pg_read_file('/home/xyz')::bytea);

Manuale

19
User2397

Questa soluzione non è esattamente efficiente in termini di runtime, ma è banalmente facile rispetto alla creazione di intestazioni personalizzate per COPY BINARY. Inoltre, non richiede librerie o linguaggi di scripting al di fuori di bash.

Innanzitutto, converti il ​​file in un hexdump, raddoppiando la dimensione del file. xxd -p ci avvicina abbastanza, ma introduce alcune fastidiose novità di cui dobbiamo occuparci:

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

Successivamente, importa i dati in PostgreSQL come un campo text molto grande. Questo tipo contiene fino a un GB per valore di campo, quindi dovremmo essere a posto per la maggior parte degli scopi:

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

Ora che i nostri dati sono una stringa esadecimale di dimensioni grandi, utilizziamo decode di PostgresQL per inserirli in un tipo bytea:

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

rispondi con xxd è bello e, per file di piccole dimensioni, molto veloce. Di seguito è riportato uno script di esempio che sto utilizzando.

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
5
user1555

Usa la funzione Postgres COPY BINARY . Questo è sostanzialmente equivalente alle tabelle esterne di Oracle .

1
Gaius

Ecco come farlo senza i privilegi di superutente (come su Heroku).

\lo_import '/cygdrive/c/Users/Chloe/Downloads/Contract.pdf'
update contracts set contract = lo_get(:LASTOID) where id = 77;

Puoi usare \lo_list per vedere gli oggetti di grandi dimensioni e \lo_unlink per eliminarli. Il campo contract nel mio esempio è bytea.

     Column      |            Type             |
contract         | bytea                       |
0
Chloe