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


38

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

Ho una tabella contenente un integercampo chiave primaria e un byteacampo. Vorrei inserire i dati nel byteacampo. Questo, presumibilmente, può essere fatto da una delle PL/lingue, e potrei cercare di farlo PL/Pythonin 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 mi preoccupo a questo punto in quanto gli utenti al momento non inseriscono byteadati. 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 byteautilizzati i campi allora?

Modifica: questa domanda simile del 2005 rimane senza risposta.

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


1
Il collegamento ai documenti psycopg è interrotto e la mia modifica sembra essere stata respinta (!?). Ecco la posizione attuale .
Aryeh Leib Taurog,

@AryehLeibTaurog: grazie. Ho rifiutato la modifica perché non mi era chiaro che il testo modificato fosse un collegamento ipertestuale. Se desideri apportare di nuovo la modifica, la approverò.
SabreWolfy,

@Andriy_M Perché pensi che "Questa modifica si discosta dall'intento originale del post". (La modifica è stata effettuata da informatik01?)
miracle173

@ miracle173: Perché ho avuto l'impressione che alcuni dei tag suggeriti fossero irrilevanti (beh, solo uno in realtà blob). Se è stato un errore, mi scuso sinceramente.
Andriy M,

Risposte:


27

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 sarebbe necessario:

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');

Per il processo inverso, non ho provato questo , ma se funziona, lo_export sarà tutto ciò di cui hai bisogno
Jack Douglas,


15

Questa soluzione non è esattamente efficiente in termini di runtime, ma è banalmente facile rispetto alla creazione delle proprie intestazioni 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 -pci avvicina molto, ma introduce alcune fastidiose novità che dobbiamo occuparci di:

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

Successivamente, importa i dati in PostgreSQL come un textcampo 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, usiamo PostgresQL decodeper inserirli in un byteatipo:

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

Questa soluzione comporta la rimozione di \ n caratteri dal file.
SabreWolfy,

2
SabreWolfy: No, non lo fa. The tr -d '\n'opera sull'output di xxd, che codifica il contenuto binario dell'input come caratteri esadecimali ASCII (0-9 e af). xxd accade anche ai feed di linea di output a intervalli regolari per rendere l'output leggibile dall'uomo, ma in questo caso li vogliamo rimuovere. I feed di riga nei dati originali saranno in formato esadecimale e rimarranno inalterati.
Goodside

5

La risposta con xxd è piacevole 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

1

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


Grazie. Il collegamento che hai indicato indica che i dati devono essere in formato tabella binaria ASCII o PostgreSQL. Più in basso nella pagina, viene menzionato che il formato della tabella binaria viene prima creato con un comando COPY TO. Uno di questi approcci mi permetterebbe di inserire un file binario (PDF, documento, foglio di calcolo) in una byteacolonna?
SabreWolfy,

La documentazione PostgreSQL su COPY BINARY ( postgresql.org/docs/8.4/interactive/sql-copy.html ) indica che è richiesta un'intestazione di file speciale quando si inseriscono dati binari. Devo creare questa intestazione e aggiungerla ai dati binari? Ciò sembra alquanto complesso per la semplice memorizzazione di una stringa di dati binari.
SabreWolfy,

Hmm, ora che me lo dici non sono sicuro, mi sono appena ricordato del comando e ho pensato che lo avrebbe fatto. Forse PL / qualunque sia l'unico modo per farlo.
Gaius,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.