Enregistrement des données dans un Blob
Comme exemple d’enregistrement de Blob, considérons la fonction du contenu du lecteur du Blob à partir du fichier.
Note
|
Cet exemple est une version adaptée des fonctions UDF pour la lecture et l’enregistrement de BLOB depuis/vers un fichier. L’UDF original est disponible à l’adresse suivante blobsaveload.zip |
Les utilitaires de lecture et d’enregistrement de Blob depuis/vers le fichier sont délivrés sous la forme d’un package
CREATE PACKAGE BlobFileUtils
AS
BEGIN
PROCEDURE SaveBlobToFile(ABlob BLOB, AFileName VARCHAR(255) CHARACTER SET UTF8);
FUNCTION LoadBlobFromFile(AFileName VARCHAR(255) CHARACTER SET UTF8) RETURNS BLOB;
END^
CREATE PACKAGE BODY BlobFileUtils
AS
BEGIN
PROCEDURE SaveBlobToFile(ABlob BLOB, AFileName VARCHAR(255) CHARACTER SET UTF8)
EXTERNAL NAME 'BlobFileUtils!SaveBlobToFile'
ENGINE UDR;
FUNCTION LoadBlobFromFile(AFileName VARCHAR(255) CHARACTER SET UTF8) RETURNS BLOB
EXTERNAL NAME 'BlobFileUtils!LoadBlobFromFile'
ENGINE UDR;
END^
Inscrivons les classes de nos procédures et de nos fonctions :
function firebird_udr_plugin(AStatus: IStatus; AUnloadFlagLocal: BooleanPtr;
AUdrPlugin: IUdrPlugin): BooleanPtr; cdecl;
begin
// enregistrable
AUdrPlugin.registerProcedure(AStatus, 'SaveBlobToFile', TSaveBlobToFileProcFactory.Create());
AUdrPlugin.registerFunction(AStatus, 'LoadBlobFromFile', TLoadBlobFromFileFuncFactory.Create());
theirUnloadFlag := AUnloadFlagLocal;
Result := @myUnloadFlag;
end;
Dans ce cas, nous donnons un exemple uniquement pour la fonction de lecture de BLOB depuis le fichier, l’exemple complet d’udr peut être téléchargé à BlobSaveLoad La partie interface du module avec une description de la fonction Loadblobfromfile
est la suivante :
interface
uses
Firebird, Classes, SysUtils;
type
// Messages d'entrée de la fonction
TInput = record
filename: record
len: Smallint;
str: array [0 .. 1019] of AnsiChar;
end;
filenameNull: WordBool;
end;
TInputPtr = ^TInput;
// Fonction de sortie
TOutput = record
blobData: ISC_QUAD;
blobDataNull: WordBool;
end;
TOutputPtr = ^TOutput;
// fonctionnalités de réalisation Loadblobfromfile
TLoadBlobFromFileFunc = class(IExternalFunctionImpl)
public
procedure dispose(); override;
procedure getCharSet(AStatus: IStatus; AContext: IExternalContext;
AName: PAnsiChar; ANameSize: Cardinal); override;
procedure execute(AStatus: IStatus; AContext: IExternalContext;
AInMsg: Pointer; AOutMsg: Pointer); override;
end;
// Classe permettant de créer une copie de la fonction externe Loadblobfromfile
TLoadBlobFromFileFuncFactory = class(IUdrFunctionFactoryImpl)
procedure dispose(); override;
procedure setup(AStatus: IStatus; AContext: IExternalContext;
AMetadata: IRoutineMetadata; AInBuilder: IMetadataBuilder;
AOutBuilder: IMetadataBuilder); override;
function newItem(AStatus: IStatus; AContext: IExternalContext;
AMetadata: IRoutineMetadata): IExternalFunction; override;
end;
Nous ne donnons que l’implémentation de la classe Execute de base tloadblobfromfile
, les autres classes de classes sont élémentaires.
procedure TLoadBlobFromFileFunc.execute(AStatus: IStatus;
AContext: IExternalContext; AInMsg: Pointer; AOutMsg: Pointer);
const
MaxBufSize = 16384;
var
xInput: TInputPtr;
xOutput: TOutputPtr;
xFileName: string;
xStream: TFileStream;
att: IAttachment;
trx: ITransaction;
blob: IBlob;
buffer: array [0 .. 32767] of Byte;
xStreamSize: Integer;
xBufferSize: Integer;
xReadLength: Integer;
begin
xInput := AInMsg;
xOutput := AOutMsg;
if xInput.filenameNull then
begin
xOutput.blobDataNull := True;
Exit;
end;
xOutput.blobDataNull := False;
// Nous obtenons le nom du fichier
xFileName := TEncoding.UTF8.GetString(TBytes(@xInput.filename.str), 0,
xInput.filename.len * 4);
SetLength(xFileName, xInput.filename.len);
// Nous lisons le fichier dans le flux
xStream := TFileStream.Create(xFileName, fmOpenRead or fmShareDenyNone);
att := AContext.getAttachment(AStatus);
trx := AContext.getTransaction(AStatus);
blob := nil;
try
xStreamSize := xStream.Size;
// Déterminer la taille maximale du tampon (segment)
if xStreamSize > MaxBufSize then
xBufferSize := MaxBufSize
else
xBufferSize := xStreamSize;
// Nous créons un nouveau Blob
blob := att.createBlob(AStatus, trx, @xOutput.blobData, 0, nil);
// Nous lisons le contenu du flux et l'écrivons dans le Blob
while xStreamSize <> 0 do
begin
if xStreamSize > xBufferSize then
xReadLength := xBufferSize
else
xReadLength := xStreamSize;
xStream.ReadBuffer(buffer, xReadLength);
blob.putSegment(AStatus, xReadLength, @buffer[0]);
Dec(xStreamSize, xReadLength);
end;
// Ferme le Blob
// La méthode CLOSE en cas de succès combine l'interface IBLOB
// L'appel suivant n'est donc pas nécessaire
blob.close(AStatus);
blob := nil;
finally
if Assigned(blob) then
blob.release;
trx.release;
att.release;
xStream.Free;
end;
end;
Tout d’abord, il est nécessaire de créer un nouveau Blob et de le lier dans la sortie Blobid à l’aide de la méthode createBlob
de IAttachment
.Étant donné que nous écrivons un objet blob temporaire pour notre base de données, nous allons le créer dans le contexte de la connexion actuelle. Le contexte de la connexion en cours et le contexte de la transaction en cours peuvent être obtenus à partir du contexte de la procédure, de la fonction ou du déclencheur externe (le IExternalContext
).
Comme dans le cas de la lecture de données à partir d’un objet blob, l’enregistrement est effectué par segmentation à l’aide de la méthode putSegment
IBlob
jusqu’à ce que les données du flux de fichiers soient terminées. Une fois l’enregistrement des données terminé dans Blob, il est nécessaire de le fermer à l’aide de la méthode close
.
Important
|
Important
La méthode |