it-swarm.asia

Bagaimana cara memasukkan (file) data ke dalam kolom bytea PostgreSQL?

Pertanyaan ini bukan tentang bytea v. Oid v. Gumpalan v. Benda besar, dll.

Saya memiliki tabel yang berisi bidang kunci utama integer dan bidang bytea. Saya ingin memasukkan data ke dalam bidang bytea. Ini bisa, mungkin, dilakukan oleh salah satu dari PL/ bahasa, dan saya mungkin ingin melakukan ini dengan PL/Python di masa depan.

Karena saya masih menguji dan bereksperimen, saya hanya ingin memasukkan data dari file (di server) menggunakan pernyataan SQL "standar". Saya menyadari bahwa hanya administrator dengan izin menulis di server yang dapat memasukkan data dengan cara yang saya inginkan. Saya tidak khawatir tentang itu pada tahap ini karena pengguna tidak akan memasukkan data bytea saat ini. Saya telah mencari berbagai situs StackExchange, Arsip PostgreSQL dan Internet secara umum, tetapi belum dapat menemukan jawabannya.

Edit: Ini diskusi dari 2008 menyiratkan bahwa apa yang ingin saya lakukan tidak mungkin. Lalu bagaimana cara bytea digunakan?

Edit: Ini pertanyaan serupa dari tahun 2005 tetap tidak terjawab.

Diselesaikan: Detail yang diberikan di sini di situs web psycopg memberikan dasar untuk solusi yang saya tulis dalam Python. Dimungkinkan juga untuk memasukkan data biner ke dalam kolom bytea menggunakan PL/Python. Saya tidak tahu apakah ini mungkin menggunakan SQL "murni".

40
SabreWolfy

sebagai superuser:

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 diperkenalkan pada 9,4 sehingga untuk versi yang lebih lama Anda perlu:

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

kemudian:

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

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

Sebagai contoh,

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

Manual

19
User2397

Solusi ini tidak terlalu efisien dalam hal runtime, tapi itu mudah dibandingkan dengan membuat header Anda sendiri untuk COPY BINARY. Selain itu, tidak memerlukan pustaka atau bahasa skrip di luar bash.

Pertama, konversikan file menjadi hexdump, gandakan ukuran file. xxd -p membuat kita cukup dekat, tetapi ada beberapa baris baru yang mengganggu yang harus kita tangani:

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

Selanjutnya, impor data dalam PostgreSQL sebagai bidang text yang sangat besar. Jenis ini dapat menampung hingga satu GB per nilai bidang, jadi kami seharusnya baik-baik saja untuk sebagian besar tujuan:

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

Sekarang data kami adalah string hex yang sangat besar, kami menggunakan decode PostgresQL untuk memasukkannya ke dalam tipe bytea:

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

jawaban dengan xxd Bagus dan, untuk file kecil, sangat cepat. Di bawah ini adalah contoh skrip yang saya gunakan.

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

Gunakan fungsi Postgres COPY BINARY . Ini secara umum setara dengan Oracle tabel eksternal .

1
Gaius

Inilah cara melakukannya tanpa hak superuser (seperti pada Heroku).

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

Kamu bisa menggunakan \lo_list untuk melihat objek besar, dan \lo_unlink untuk menghapusnya. Bidang contract dalam contoh saya adalah bytea.

     Column      |            Type             |
contract         | bytea                       |
0
Chloe