Beispiel update Blob-Feld

Themen rund um den praktischen Einsatz von Firebird. Fragen zu SQL, Performance, Datenbankstrukturen, etc.

Moderator: thorben.braun

bfuerchau
Beiträge: 276
Registriert: Mo 7. Mai 2018, 18:09

Schön wäre es, wenn die Dokumentation auf die Parameter "?" mal etwas stärker eingeht.
Wie gehe ich damit um:

Select * from MyTable where F1 = ? and F2 = ? and F3 between ? and ?

Analog dazu ein Delete, Update und einen Insert:

insert into mytable (F1, F2, ..., FN) values(?, ?, ..., ?)

Hervorzuheben ist dabei die z.T. drastische Beschleunigung (bis Faktor 100) wenn man mit prepared Statements und typisierten Parametern umgeht.
Hamburgo
Beiträge: 46
Registriert: Di 28. Mai 2019, 17:28

Hallo Martin,

das wäre ja echt der Hammer, wenn wir das zusammen hinbekommen.

Um Deinen Code hier lokal ausprobieren zu können, müsste ich wohl wissen, wie Deine Tabelle TBL_TEST angelegt ist.

Bitte poste mir den Create-String.

Und um überprüfen zu können, ob das Blob auch korrekt gespeichert wurde, bräuchte es wohl auch noch einen Code, wie ich das Blob wieder exportiere ?
Hamburgo
Beiträge: 46
Registriert: Di 28. Mai 2019, 17:28

Hallo Martin,

so den 1. Teil habe ich wohl erfolgreich hier bei mir lokal
nachbilden können.

Ich habe eine Tabelle TBL_TEST erstellt, wie ich glaube, dass sie aufgebaut sein muss.

Dann habe ich Dein Script laufen lassen und habe nun einen Datensatz,
wo im Feld pdf_bin mir der IbExpert den Wert BLOB anzeigt.

Um überprüfen zu können, ob mein Muster-Bild korrekt gespeichert wurde, bräuchte ich wohl jetzt einen Teil mit dem ich das Blob wieder exportieren kann.

Also ein Script, mit dem ich einen Select auf den Datensatz absetze, um die Blob-Id zu erhalten, mit Hilfe dieser die Segmente lade und wieder in einem String zusammensetze und mit file_put_contents exportiere ?

Ich wäre Dir sehr verbunden, wenn Du mir sowas noch geben könntest.

Herzlichen Dank im Voraus.
Benutzeravatar
martin.koeditz
Beiträge: 283
Registriert: Sa 31. Mär 2018, 14:35

Hallo,

die Test-Tabelle ist recht einfach aufgebaut:

Code: Alles auswählen

CREATE TABLE TBL_TEST 
(
  FIRST_NAME              VARCHAR(    32)  COLLATE UTF8,
  IS_ENABLED              BOOLEAN         DEFAULT false NOT NULL,
  PDF_BIN                    BLOB
);
Zum Extrahieren nutze ich auch wieder eine Hilfsfunktion. Diese baut den gesamten Binär-String zusammen.

Code: Alles auswählen

function blob_extract($blobField) {
    
    if (!$blobField)
        return null;
    
    list ($length, $numseg, $maxseg, $stream, $isnull) = ibase_blob_info($blobField);
    $data = null;
    $blobhandle = ibase_blob_open($blobField);
    for($i = 0; $i < $numseg; $i++){
        $readsize = $maxseg;
        if($i == ($numseg - 1)){
            $readsize = $length - (($numseg - 1) * $maxseg);
        }
        $data .= ibase_blob_get($blobhandle, $readsize);
    }
    ibase_blob_close($blobhandle);
    
    return $data;
}
Zu guter Letzt noch der Abruf:

Code: Alles auswählen

if(($dbh = ibase_connect('10.1.12.200:/srv/firebird/db01.fdb', 'sysdba', 'masterkey')) === false)
        die(ibase_errmsg ());

$result = ibase_query($dbh, "SELECT * FROM TBL_TEST where first_name like 'Martin'") or die(ibase_errmsg());
$data = ibase_fetch_object($result);

// Bild ausgeben
header('Content-Type: image/jpeg');
echo blob_extract($data->PDF_BIN); 
Anders als der Name des Felder PDF_BIN vermuten lässt, habe ich hier ein Bild gespeichert.

Gruß
Martin
Martin Köditz
it & synergy GmbH
bfuerchau
Beiträge: 276
Registriert: Mo 7. Mai 2018, 18:09

Warum wird bei einem konstanten Wert hier "like" verwendet?

....first_name like 'Martin'

Performanter wird dies mit

first_name = 'Martin'

Like ist nur erforderlich wenn man mit Wildcards umgeht, also
'Martin%' oder '%Martin'.
Wenn man sowas häufiger macht ist es kein Wunder, dass die Abfragen langsam sind und bei steigendem Datenvolumen immer langsamer werden.
Hamburgo
Beiträge: 46
Registriert: Di 28. Mai 2019, 17:28

Hallo Martin,

herzlichen Dank für die Abruf-Sequenz, die ich gleich mal anwenden werde.

Zwischenzeitlich habe ich diesen Abschnitt für die Ausgabe erfolgreich nutzen können:

Code: Alles auswählen

$blobinfo = ibase_blob_info($blob);

$blobhandle = ibase_blob_open($blob);

for($i = 0; $i < $blobinfo[1]; $i++){
$readsize = $blobinfo[2];
if($i == ($blobinfo[1] - 1)){
$readsize = $blobinfo[0] - (($blobinfo[1] - 1) * $blobinfo[2]);
}
$totalimage .= ibase_blob_get($blobhandle, $readsize);
}
ibase_blob_close($blobhandle);

file_put_contents(Cache.'Scan_1924_B.pdf', $totalimage);
Hamburgo
Beiträge: 46
Registriert: Di 28. Mai 2019, 17:28

Hallo Martin,

es könnte alles so schön sein, wenn ein kleiner Rest jetzt auch noch funktionieren würde.

Tut es aber leider nicht.

Das Einlesen und das wieder ausgeben eines Blobs funktioniert perfekt, nur mit dem
Speichern der Blob-ID habe ich noch Probleme.

1. Beim Erstellen eines Blobs vergibt er immer dieselbe Blob-ID, nämlich
0x0000000100000000, egal wieviele Grafiken ich einlese.

2. Mit dieser Blob-ID kann ich auch wunderbar das Blob wieder unter einem
anderem Namen exportieren.

3. Beim Update kommt in dem Datensatz aber die Blob-ID 0x000003c400000080
an, auch immer dieselbe, egal wieviele Grafiken ich einlese.

4. Mit der Blob-ID 0x000003c400000080 scheitert dann der Export. Das Script meldet
dann keinen Fehler, aber die Ausgabe-Datei hat dann 0 KB.

Was mache ich noch falsch ?
Hamburgo
Beiträge: 46
Registriert: Di 28. Mai 2019, 17:28

Braucht es vielleicht noch einen Trigger, um die Blob-IDs zu generieren ?

Oder hat das wieder etwas mit UTF8 zu tun ?
Benutzeravatar
martin.koeditz
Beiträge: 283
Registriert: Sa 31. Mär 2018, 14:35

Guten Morgen,

das Erzeugen der BLOB-IDs übernimmt Firebird selbst.

Folgender Code speichert die Blobs hintereinander in der DB. Damit gibt es keine Schwierigkeiten.

Code: Alles auswählen

// Bild in DB schreiben
$blob = blob_create(file_get_contents('/media/koeditz.jpg'));
$query = ibase_query($dbh, "UPDATE TBL_TEST set pdf_bin = ? where first_name = 'Martin'", $blob) or die(ibase_errmsg());

// PDF in DB schreiben
$blob = blob_create(file_get_contents('/media/zugferd.pdf'));
$query = ibase_query($dbh, "UPDATE TBL_TEST set pdf_bin = ? where first_name ='Marcus'", $blob) or die(ibase_errmsg());
Wenn in der DB die gleichen BLOB-IDs landen, dann wird keine neue BLOB-ID erzeugt. Die Hilfsfunktion blob_create($data) erzeugt dann keine neue ID. Bitte überprüfe die korrekte Übergabe deiner Daten. Existiert die Quelldatei wirklich am angegebenen Pfad?

Gruß
Martin
Martin Köditz
it & synergy GmbH
Hamburgo
Beiträge: 46
Registriert: Di 28. Mai 2019, 17:28

Guten Morgen Martin,

jubel, jetzt funktioniert das auch mit der Blob-ID !!!

:D :D :D
Antworten