Comment insérer des données (fichier) dans une colonne de bytea PostgreSQL?


38

Cette question ne concerne pas bytea v. Oid v. Blobs v. Gros objets, etc.

J'ai une table contenant un integerchamp de clé primaire et un byteachamp. J'aimerais entrer des données sur le byteaterrain. Cela peut vraisemblablement être fait par l’une des PL/langues, et j’envisagerai peut-être de le faire PL/Pythondans le futur.

Comme je suis toujours en train de tester et d’expérimenter, je voudrais simplement insérer des données d’un fichier (sur le serveur) en utilisant des instructions SQL "standard". Je suis conscient que seuls les administrateurs ayant des droits en écriture sur le serveur pourraient insérer les données comme je le souhaiterais. Je ne m'inquiète pas de cela à ce stade car les utilisateurs ne seraient pas en train d'insérer des byteadonnées pour le moment. J'ai consulté les différents sites StackExchange, les archives PostgreSQL et Internet en général, mais je n'ai pas trouvé de réponse.

Edit: Cette discussion de 2008 implique que ce que je veux faire n'est pas possible. Comment les byteachamps sont-ils utilisés alors?

Edit: Cette question similaire de 2005 reste sans réponse.

Résolu: Les détails fournis ici sur le psycopgsite Web 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 byteacolonne à l'aide de PL/Python. Je ne sais pas si cela est possible en utilisant du SQL "pur".


1
Le lien vers les documents psycopg est cassé et mon édition semble avoir été rejetée (!?). Voici l'emplacement actuel .
Aryeh Leib Taurog

@ AryehLeibTaurog: Merci. J'ai rejeté la modification car il n'était pas clair pour moi que votre texte modifié était un lien hypertexte. Si vous souhaitez refaire l'édition, je l'approuve.
SabreWolfy

@Andriy_M Pourquoi pensez-vous que "Cette modification est différente de l'intention originale du message." (Le montage effectué par informatik01?)
miracle173

@ miracle173: Parce que j'ai eu l'impression que certaines des balises suggérées n'étaient pas pertinentes (enfin, une seule, en fait blob). Si c'était une erreur, je m'excuse sincèrement.
Andriy M

Réponses:


27

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 dans la version 9.4, donc pour les versions plus anciennes, il vous faudrait:

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

Pour l’inverse, je n’ai pas essayé cela , mais si ça marche, lo_export sera tout ce dont vous avez besoin
Jack Douglas


15

Cette solution n’est pas vraiment efficace en termes d’exécution, mais elle est très simple comparée à la création de vos propres en-têtes COPY BINARY. De plus, il ne nécessite aucune bibliothèque ou langage de script en dehors de bash.

Commencez par convertir le fichier en hexdump, en doublant sa taille. xxd -pCela nous rapproche beaucoup, mais cela introduit des nouvelles lignes gênantes dont nous devons nous occuper:

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

Ensuite, importez les données dans PostgreSQL sous forme de très grand textchamp. Ce type contient jusqu'à un Go par valeur de champ, nous devrions donc pouvoir nous en tirer dans la plupart des cas:

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

Maintenant que nos données sont une chaîne hex gratuitement grande, nous utilisons PostgresQL decodepour les obtenir dans un byteatype:

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

Cette solution entraîne cependant la suppression des caractères du fichier.
SabreWolfy

2
SabreWolfy: Non, pas du tout. Le tr -d '\n'fonctionne sur la sortie de xxd, qui code le contenu binaire de l'entrée sous forme de caractères hexadécimaux ASCII (0-9 et af). xxd arrive également à produire des sauts de ligne à intervalles réguliers pour rendre la sortie lisible par l'homme, mais dans ce cas, nous souhaitons leur suppression. Les sauts de ligne dans les données d' origine seront sous forme hexadécimale et ne seront pas affectés.
Goodside

5

La réponse avec xxd est sympa et, pour les petits fichiers, très rapide. Vous trouverez ci-dessous 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

1

Utilisez la fonction Postgres COPY BINARY . Ceci est globalement équivalent aux tables externes d'Oracle .


Merci. Le lien que vous avez indiqué indique que les données doivent être au format ASCII ou au format de tableau binaire de PostgreSQL. Plus bas dans la page, il est mentionné que le format de tableau binaire est d'abord créé avec une commande COPY TO. Est-ce que l'une ou l'autre de ces approches me permettrait d'insérer un fichier binaire (PDF, document, feuille de calcul) dans une byteacolonne?
SabreWolfy

La documentation de PostgreSQL sur COPY BINARY ( postgresql.org/docs/8.4/interactive/sql-copy.html ) indique qu'un en-tête de fichier spécial est requis lors de l'insertion de données binaires. Dois-je créer cet en-tête et l'ajouter à des données binaires? Cela semble assez complexe pour stocker simplement une chaîne de données binaires.
SabreWolfy

Hmm, maintenant que vous en parlez, je ne suis pas sûr, je viens de me souvenir du commandement et je pensais qu'il ferait cela. Peut-être PL / quel que soit le seul moyen de le faire.
Gaius
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.