Dateiimport mit bytea

JayCole

Aktiver Benutzer
Beiträge
35
Guten Morgen zusammen,

es gibt so viele Treffer zu dem Thema im Netz und doch fehlt mir scheinbar noch ein Puzzleteil.
Nachdem eine entsprechende Tabelle erstellt wurde soll es mit folgender Codezeile möglich sein Dateien in Postgres abzulegen:
INSERT INTO tbl_document ( id, info, doc ) VALUES ( 2, 'Daily Report', pg_read_file('report.doc')::bytea );

In diesem Beispiel wollte jemand ein Word-Dokument importieren. Aber woher weiß Postgres WO dieses Dokument liegt? Ich muss doch irgendwo den kompletten Pfad eingeben 🤔

Für Eure Zeit und den Schubs in die richtige Richtung bedanke ich mich schon vielmals im Voraus 😊
 
Werbung:
Aber woher weiß Postgres WO dieses Dokument liegt? Ich muss doch irgendwo den kompletten Pfad eingeben
pg_read_file liest nur Dateien die auf dem Postgres Server liegen - nicht Dateien die auf dem Client liegen (da wo z.B. psql ausgeführt wird).

Wo diese Funktion die Datei erwartet ist im Handbuch beschrieben
Only files within the database cluster directory and the log_directory can be accessed, unless the user is a superuser or is granted the role pg_read_server_files. Use a relative path for files in the cluster directory, and a path matching the log_directory configuration setting for log files
D.h. wenn Dein Befehl funktioniert, hat wohl irgendjemand die Word Datei vorher auf den Postgres Server an die richtige Stelle kopiert.
 
Hallo castorp,

herzlichen Dank für Deine schnelle Antwort und den Link.

Heißt das im Umkehrschluss, dass es keine Möglichkeit gibt direkt auf beliebige Client-Pfade zuzugreifen? Ich müsste also einen Workaround einbauen, mit dem ich die benötigten Dateien von meinem beliebigen Pfad zunächst auf den Postres Server an die richtige Stelle kopiere, um dann die Datei in die Datenbank zu laden?

Und wenn dem so ist, dann kann umgekehrt keiner meiner Anwender, sofern er nicht superuser ist oder eben pg_read_server_files gewährt bekommt, die in Postgres abgelegten Dateien öffnen?

Die Herausforderung wäre nämlich eigentlich so simpel gedacht. Wir möchten Dateien aus Postgres heraus direkt öffnen können. Bislang habe ich Pfade zu den Dateien in Postgres hinterlegt, über die dann die Dateien geöffnet werden. Aber damit haben zu viele User die Möglichkeit an die Dateien zu kommen, denn der Pfad ist soweit allen frei zugänglich und ein Fileserver management ist aufgrund der vielen User seitens der IT nicht gewünscht. Über die Datenbank könnte ich die Berechtigungen selbst sehr simpel und selbständig steuern.

Nochmals Dankeschön 😊
 
Heißt das im Umkehrschluss, dass es keine Möglichkeit gibt direkt auf beliebige Client-Pfade zuzugreifen?
Genau. Jedenfalls nicht mit "SQL Mitteln".

SQL "läuft" auf dem Server, deswegen können Funktionen die Teil eines SQL Befehls sind, nicht auf Daten des Clients zugreifen.

Einige SQL Clients erlauben das mit eigenen Befehlen (von denen Postgres aber nichts weiß).

Wenn Du die Dateien auf dem Client "öffnen" willst, musst Du die Binärdaten via SQL lesen und lokal als Datei abspeichern. Dann kann Deine Anwendung die Datei öffnen. Du musst natürlich dafür sorgen, dass diese lokale Kopie auch nach dem Schliessen der Datei wieder gelöscht wird.

Die andere Richtung musst Du auch in Deiner Anwendung implementieren: lesen der Datei in ein "byte array" (wie das genau heißt, hängt von Deiner Programmiersprache ab), dann kannst Du dieses "byte array" mittels eines INSERT oder UPDATE Befehls an die Datenbank schicken.
 
Hi castorp,
das klingt ernüchternd, aber nicht hoffnungslos.
Du kennst Dich nicht zufällig auch mit VBA aus?
Ich hab´s mal short and simple ausprobiert - vielleicht viel zu short and simple? 😬
In die Richtung - also myArr As Byte, bytea, binary data - hatte ich noch nie etwas gemacht, komplett Neuland für mich, hatte hier und da im Netz bloß einige "Wegweiser" gefunden, meistens waren die Anforderungen/Anfragen allerdings recht komplex und damit auch die Lösungen umfangreicher. Daher habe ich das mal für mich stark reduziert:

Sub myArrTestForSQL()
Dim myArr() As Byte
myArr = "C:\MeinPfad\ArrTest.pdf"
cnn.Execute "INSERT INTO meinschema.meinetabelle VALUES('TEST1','" & myArr(0) & "')"
'das INSERT läuft ohne Fehlermeldung durch und in meiner Postgres-Tabelle sehe ich in der character varying Spalte 'TEST1' und in der bytea Spalte [binary data], aber was ist da wohl wirklich angekommen? Das sagt jetzt wahrscheinlich wenig aus, aber dennoch:
With rcs
.Open ("SELECT * FROM meinschema.meinetabelle " & _
"WHERE name = 'TEST1'"), cnn, adOpenDynamic, adLockReadOnly
Debug.Print .Fields("datei").Value 'liefert ein Fragezeichen, also einfach nur ?
.Close
End With
Set rcs= Nothing
End Sub

Abgesehen von der Frage, ob ich es mit der Reduzierung nicht stark übertrieben habe, stellt sich mir noch die Frage, ob der Debug.Print hier überhaupt etwas anderes als ein Fragezeichen liefern könnte.

Wie könnte man denn wohl die Binärdaten via SQL lesen und lokal als Datei abspeichern, um sie dann zu öffnen, wie Du es geschrieben hast?
 
Hallo noch mal,
nach einer kurzen Zwangspause wärme ich das Thema nochmal auf und wäre Euch für einen weiteren Austausch sehr dankbar!
Mit der folgenden Zeile in pgAdmin konnte ich offensichtlich ebenfalls eine Datei importieren:
Code:
INSERT INTO meinschema.meinetabelle(jpgname,jpgpic) VALUES('MeineDatei', bytea('C:\\MeinPfad\\ArrTest.pdf'));
Hierbei scheinen die doppelten Backslashes im Pfad wichtig zu sein!
Über "View/Edit Data" (in pgAdmin) sehe ich eine neue Zeile mit den Spalteninhalten "MeineDatei" (character varying) und in der bytea-Spalte sehe ich [binary data].
Nun möchte ich wissen, ob da tatsächlich die pdf-Datei importiert wurde. Aber wie kriege ich sie geöffnet oder wieder lokal gespeichert?
Castorp schrieb an sich:
SQL "läuft" auf dem Server, deswegen können Funktionen die Teil eines SQL Befehls sind, nicht auf Daten des Clients zugreifen.
Dennoch habe ich mit dem o. g. Insert scheinbar einen Import durchführen können.
Sollte das tatsächlich geklappt haben, würde es mich wundern, wenn ich nicht in ähnlicher Weise rückwärts gehen könnte.
Und an sich schrieb Castorp weiter:
Wenn Du die Dateien auf dem Client "öffnen" willst, musst Du die Binärdaten via SQL lesen und lokal als Datei abspeichern. Dann kann Deine Anwendung die Datei öffnen.
Aber wie?
Ausprobiert hatte ich schon:
Code:
COPY (SELECT jpgpic FROM meinschema.meinetabelle WHERE jpgname = 'MeineDatei') TO 'C:\\MeinPfad\\DL\\ArrTest.pdf' (FORMAT binary);
Hier heißt es: ERROR: FEHLER: relativer Pfad bei COPY in Datei nicht erlaubt
Und die im www oft genannte Funktion pg_read_binary_file meckert bereits über die Funktion selbst mit: ERROR: FEHLER: Syntaxfehler bei »pg_read_binary_file«
Ich hatte mich außerdem an encode, hex, base64 ausgetobt, alles ohne Erfolg.
Also, wie kann ich herausfinden, ob das INSERT geklappt hat und wie kriege ich den Output/Download der binary data wieder hin? (ggf. über VBA)
Tausend Dank schon im Voraus für Eure Zeit ☺️
 
Hallo Akretschmer,
besten Dank für den Link. Nein, ehrlich gesagt habe ich da nicht viel von verstanden 😬
Könntest Du mir zunächst bestätigen, ob mein INSERT wohl funktioniert hat? Ob ich wirklich mit einem gelungenden Import der pdf-Datei rechnen kann?
Und dann eben der Output, wie zuvor beschrieben (?).
Mir dürfte da leider einwenig Erfahrung insgesamt fehlen 😕
 
Dennoch habe ich mit dem o. g. Insert scheinbar einen Import durchführen können.
Vermutlich weil Postgres bei Dir lokal auf Deinem Desktop/Laptop läuft.
Läuft Postgres aber auf einem zentralen Rechner (und nicht auf dem Rechner auf dem Dein SQL client läuft), dann gibt es die Datei 'C:\\MeinPfad\\ArrTest.pdf' ja gar nicht.
 
Dein Insert schreibt nicht den Inhalt der Datei in das Feld, sondern den Parameter der Funktion bytea(), als bytea konvertiert:

Code:
postgres=# select bytea('C:\\MeinPfad\\ArrTest.pdf');
                      bytea                       
--------------------------------------------------
 \x433a5c4d65696e506661645c417272546573742e706466
(1 row)

Sehr sicher hast Du exakt dasselbe in Deiner Tabelle ;-)
 
schau dir doch einfach an, was ich da mache
Ja, das tue ich und muss direkt über solche Sätze schmunzeln und fühle mich zugleich klein, weil ich es schlicht weg nicht verstehe:
Ich blase das also aus psql als Base64-codierten Kram raus, pipe es durch base64 (ein Tool) und dekodiere es wieder zurück in Hex und speicher das als Datei. md5sum ist gleich der Ursprungsdatei.
Aber zur Sache. Selbst
select id, filename, left(filecontent,100) from pdf_store;
führt mit meinen Parametern direkt zu einem Fehler:

ERROR: FEHLER: Funktion left(bytea, integer) existiert nicht
LINE 1: select jpgname, left(jpgpic,100) from meinschema.meinetabelle...
^
HINT: Keine Funktion stimmt mit dem angegebenen Namen und den Argumenttypen überein. Sie müssen möglicherweise ausdrückliche Typumwandlungen hinzufügen.
SQL state: 42883
Character: 17

Typumwandlung? Hast Du in Deiner Code-Zeile auch nicht 🤔
 
Werbung:
Zurück
Oben