Come inserire i dati (file) in una colonna bytea PostgreSQL?
-
16-10-2019 - |
Domanda
Questa domanda non riguarda bytea v. OID v. Blob v. Oggetti di grandi dimensioni, ecc
Ho una tabella che contiene un campo integer
chiave primaria e un campo bytea
. Mi piacerebbe inserire i dati nel campo bytea
. Questo può, presumibilmente, essere fatto da una delle lingue PL/
, e posso guardare in questo modo con PL/Python
in futuro.
Mentre sto ancora testando e sperimentando, vorrei semplicemente inserire i dati da un file (sul server) utilizzando le istruzioni SQL "standard". Sono consapevole del fatto che solo gli amministratori con i permessi di scrittura sul server sarebbe in grado di inserire i dati nel modo vorrei. Io non sono preoccupato per che in questa fase, gli utenti non sarebbero l'inserimento dei dati bytea
attualmente. Ho cercato i vari siti StackExchange, l'Archivio di PostgreSQL e di Internet in generale, ma non sono stati in grado di trovare una risposta.
Modifica Questa discussione dal 2008 implica che ciò che voglio fare non è possibile. Come vengono utilizzati i campi bytea
allora?
Modifica Questo domanda simile da 2005 rimane senza risposta.
Risolto: I dati forniti qui sul sito psycopg
fornito la base per una soluzione che ho scritto in Python. Può anche essere possibile inserire dati binari in una colonna bytea
utilizzando PL/Python
. Non so se questo è possibile utilizzando SQL "puro".
Soluzione
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 così per le versioni precedenti voi avrebbe 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;$$;
quindi:
insert into my_table(bytea_data) select bytea_import('/my/file.name');
Altri suggerimenti
Questa soluzione non è esattamente efficiente in termini di tempo di esecuzione, ma è banalmente facile rispetto a fare le proprie intestazioni per COPY BINARY
. Inoltre, non richiede librerie o linguaggi di scripting di fuori di bash.
In primo luogo, convertire il file in un hexdump, raddoppiando le dimensioni del file. xxd -p
noi diventa piuttosto vicino, ma getta in alcune nuove righe fastidiosi che dobbiamo prendere cura di:
xxd -p /path/file.bin | tr -d '\n' > /path/file.hex
Avanti, importare i dati in PostgreSQL come un campo molto grande text
. Questo tipo può contenere fino a un GB per ogni 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 è una grande gratuitamente stringa esadecimale, usiamo decode
di PostgreSQL per farlo in un tipo bytea
:
CREATE TABLE bindump AS SELECT decode(hex, 'hex') FROM hexdump;
La risposta con xxd è bello e, per i file di piccole dimensioni, molto veloce. Di seguito è riportato uno script di esempio che sto usando.
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
Utilizzare la Postgres copia binaria funzione. Questo è grosso modo equivalenti a Oracle di tabelle esterne .