Cette question ne concerne pas bytea v. Oid v. Blobs v. Gros objets, etc.
J'ai une table contenant un champ de clé primaire integer
et un champ bytea
. Je souhaite saisir des données dans le champ bytea
. Cela peut probablement être fait par l'un des PL/
langues, et je pourrais envisager de le faire avec PL/Python
A l'avenir.
Comme je teste et expérimente encore, je voudrais simplement insérer des données à partir d'un fichier (sur le serveur) en utilisant des instructions SQL "standard". Je suis conscient que seuls les administrateurs disposant d'une autorisation d'écriture sur le serveur pourraient insérer des données de la manière que je souhaiterais. Je ne suis pas préoccupé par cela à ce stade car les utilisateurs n'inséreraient pas de données bytea
pour le moment. J'ai recherché les différents sites StackExchange, les archives PostgreSQL et Internet en général, mais je n'ai pas pu trouver de réponse.
Edit: This discussion from 2008 implique que ce que je veux faire n'est pas possible. Comment les champs bytea
sont-ils alors utilisés?
Edit: This question similaire de 2005 reste sans réponse.
Résolu: Les détails fournis ici sur le site Web psycopg
ont fourni la base d'une solution que j'ai écrite en Python. Il peut également être possible d'insérer des données binaires dans une colonne bytea
à l'aide de PL/Python
. Je ne sais pas si cela est possible en utilisant du SQL "pur".
en tant que superutilisateur:
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
a été introduit en 9.4, donc pour les anciennes versions, vous auriez besoin de:
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;$$;
puis:
insert into my_table(bytea_data) select bytea_import('/my/file.name');
Utilisez pg_read_file('location_of file')::bytea
.
Par exemple,
create table test(id int, image bytea);
insert into test values (1, pg_read_file('/home/xyz')::bytea);
Cette solution n'est pas exactement efficace en termes d'exécution, mais elle est très simple par rapport à la création de vos propres en-têtes pour COPY BINARY
. De plus, il ne nécessite aucune bibliothèque ou langage de script en dehors de bash.
Tout d'abord, convertissez le fichier en hexdump, en doublant la taille du fichier. xxd -p
nous rapproche assez, mais il apporte quelques nouvelles lignes ennuyeuses dont nous devons prendre soin:
xxd -p /path/file.bin | tr -d '\n' > /path/file.hex
Ensuite, importez les données dans PostgreSQL en tant que très grand champ text
. Ce type peut contenir jusqu'à 1 Go par valeur de champ, nous devrions donc être d'accord pour la plupart des utilisations:
CREATE TABLE hexdump (hex text); COPY hexdump FROM '/path/file.hex';
Maintenant que nos données sont une chaîne hexadécimale gratuite, nous utilisons decode
de PostgresQL pour les entrer dans un type bytea
:
CREATE TABLE bindump AS SELECT decode(hex, 'hex') FROM hexdump;
Le réponse avec xxd est sympa et, pour les petits fichiers, très rapide. Voici un exemple de script que j'utilise.
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
Utilisez la fonction Postgres COPY BINARY . C'est globalement équivalent à Oracle tables externes .
Voici comment le faire sans privilèges de superutilisateur (comme sur Heroku).
\lo_import '/cygdrive/c/Users/Chloe/Downloads/Contract.pdf'
update contracts set contract = lo_get(:LASTOID) where id = 77;
Vous pouvez utiliser \lo_list
pour voir les gros objets, et \lo_unlink
pour les supprimer. Le champ contract
dans mon exemple est bytea
.
Column | Type |
contract | bytea |