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

38

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

Saya memiliki tabel yang berisi integerbidang kunci utama dan byteabidang. Saya ingin memasukkan data ke dalam byteabidang. Ini mungkin, mungkin, dilakukan oleh salah satu PL/bahasa, dan saya mungkin akan melakukan hal ini PL/Pythondi masa depan.

Karena saya masih menguji dan bereksperimen, saya hanya ingin memasukkan data dari file (di server) menggunakan pernyataan SQL "standar". Saya sadar 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 byteadata saat ini. Saya telah mencari berbagai situs StackExchange, Arsip PostgreSQL dan Internet secara umum, tetapi belum dapat menemukan jawaban.

Sunting: Diskusi ini dari 2008 menyiratkan bahwa apa yang ingin saya lakukan tidak mungkin. Bagaimana byteabidang yang digunakan?

Sunting: Pertanyaan serupa ini dari 2005 tetap tidak terjawab.

Diselesaikan: Rincian yang disediakan di sini di psycopgsitus web memberikan dasar untuk solusi yang saya tulis dengan Python. Dimungkinkan juga untuk memasukkan data biner ke dalam byteakolom menggunakan PL/Python. Saya tidak tahu apakah ini mungkin menggunakan "murni" SQL.

SabreWolfy
sumber
1
Tautan ke psycopg docs rusak dan hasil edit saya tampaknya telah ditolak (!?). Berikut adalah lokasi saat ini .
Aryeh Leib Taurog
@AryehLeibTaurog: Terima kasih. Saya menolak hasil edit karena tidak jelas bagi saya bahwa teks Anda yang diubah adalah hyperlink. Jika Anda ingin mengedit lagi, saya akan menyetujuinya.
SabreWolfy
@Andriy_M Mengapa Anda berpikir bahwa "Suntingan ini menyimpang dari maksud asli kiriman." (Suntingan dilakukan oleh informatik01?)
miracle173
@ miracle173: Karena saya mendapat kesan bahwa beberapa tag yang disarankan tidak relevan (well, sebenarnya hanya satu, blob). Jika itu adalah kesalahan, saya dengan tulus meminta maaf.
Andriy M

Jawaban:

27

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 di 9.4 jadi 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');
Jack Douglas
sumber
Untuk proses sebaliknya, saya belum mencoba ini , tetapi jika berhasil, lo_export akan menjadi yang Anda butuhkan
Jack Douglas
17

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

sudalai
sumber
2
Atau sedikit lebih sederhana pg_read_binary_file('/path/to/file'),. Lihat postgresql.org/docs/current/static/functions-admin.html
Arto Bendiken
15

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

Pertama, konversikan file menjadi hexdump, gandakan ukuran file. xxd -pmembuat 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 textbidang yang sangat besar . Jenis ini menampung hingga satu GB per nilai bidang, jadi kami harusnya oke 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 PostgresQL decodeuntuk memasukkannya ke dalam byteatipe:

CREATE TABLE bindump AS SELECT decode(hex, 'hex') FROM hexdump;
sisi baik
sumber
Solusi ini menghasilkan \ n karakter yang dihapus dari file.
SabreWolfy
2
SabreWolfy: Tidak, tidak. Ini tr -d '\n'beroperasi pada output xxd, yang mengkodekan konten biner dari input sebagai karakter heksadesimal ASCII (0-9 dan af). xxd juga terjadi pada feed garis output secara berkala untuk membuat output dapat dibaca oleh manusia, tetapi dalam hal ini kami ingin mereka dihapus. Umpan baris dalam data asli akan dalam bentuk hex, dan akan tetap tidak terpengaruh.
goodside
5

The 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
Komunitas
sumber
1

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

Gayus
sumber
Terima kasih. Tautan yang Anda berikan menunjukkan bahwa data harus dalam format tabel biner ASCII atau PostgreSQL. Lebih jauh ke bawah halaman, disebutkan bahwa format tabel biner pertama kali dibuat dengan perintah COPY TO. Apakah salah satu dari pendekatan ini memungkinkan saya untuk memasukkan file biner (PDF, dokumen, spreadsheet) ke dalam byteakolom?
SabreWolfy
Dokumentasi PostgreSQL pada COPY BINARY ( postgresql.org/docs/8.4/interactive/sql-copy.html ) menunjukkan bahwa header file khusus diperlukan ketika memasukkan data biner. Apakah saya perlu membuat tajuk ini dan menambahkannya ke data biner? Tampaknya agak rumit untuk hanya menyimpan serangkaian data biner.
SabreWolfy
Hmm, sekarang Anda menyebutkannya saya tidak yakin, saya hanya ingat perintahnya dan berasumsi akan melakukannya. Mungkin PL / apa pun adalah satu-satunya cara untuk melakukannya.
Gayus