Fonction : classe
Maintenant, nous devons écrire la classe et la fonction elle-même. Elles seront situées dans le module SumArgsFunc
. Des exemples d’écriture de procédures et de triggers seront présentés plus tard.
unit SumArgsFunc;
{$IFDEF FPC}
{$MODE DELPHI}{$H+}
{$ENDIF}
interface
uses
Firebird;
{ *********************************************************
create function sum_args (
n1 integer,
n2 integer,
n3 integer
) returns integer
external name 'myudr!sum_args'
engine udr;
********************************************************* }
type
// la structure à laquelle le message d'entrée sera associé
TSumArgsInMsg = record
n1: Integer;
n1Null: WordBool;
n2: Integer;
n2Null: WordBool;
n3: Integer;
n3Null: WordBool;
end;
PSumArgsInMsg = ^TSumArgsInMsg;
// la structure à laquelle le message de sortie sera associé
TSumArgsOutMsg = record
result: Integer;
resultNull: WordBool;
end;
PSumArgsOutMsg = ^TSumArgsOutMsg;
// Classe pour l'instanciation de la fonction externe TSumArgsFunction
TSumArgsFunctionFactory = class(IUdrFunctionFactoryImpl)
// Appelé lorsque la classe est détruite
procedure dispose(); override;
{ Exécuté chaque fois qu'une fonction externe est chargée dans le cache de métadonnées.
Permet de modifier le format des messages d'entrée et de sortie.
@param(AStatus vecteur de statut)
@param(AContext Contexte d'exécution de la fonction externe)
@param(AMetadata Métadonnées de la fonction externe)
@param(AInBuilder Constructeur de messages pour les métadonnées d'entrée)
@param(AOutBuilder Constructeur de messages pour les métadonnées de sortie)
}
procedure setup(AStatus: IStatus; AContext: IExternalContext;
AMetadata: IRoutineMetadata; AInBuilder: IMetadataBuilder;
AOutBuilder: IMetadataBuilder); override;
{ Création d'une nouvelle instance de fonction externe TSumArgsFunction
@param(AStatus vecteur de statut)
@param(AContext Contexte d'exécution de la fonction externe)
@param(AMetadata Métadonnées de la fonction externe)
@returns(Instance de la fonction externe)
}
function newItem(AStatus: IStatus; AContext: IExternalContext;
AMetadata: IRoutineMetadata): IExternalFunction; override;
end;
// Fonction externe TSumArgsFunction.
TSumArgsFunction = class(IExternalFunctionImpl)
// Appelé lorsque l'instance de la fonction est détruite
procedure dispose(); override;
{ Cette méthode est appelée juste avant l'exécution et indique au noyau le jeu de caractères
requis pour échanger des données en interne avec cette méthode. Lors de cet appel, le contexte
utilise le jeu de caractères obtenu par ExternalEngine::getCharSet.
@param(AStatus Vecteur de statut)
@param(AContext Contexte d'exécution de la fonction externe)
@param(AName Nom du jeu de caractères)
@param(ANameSize Longueur du nom du jeu de caractères)
}
procedure getCharSet(AStatus: IStatus; AContext: IExternalContext;
AName: PAnsiChar; ANameSize: Cardinal); override;
{ Exécution d'une fonction externe
@param(AStatus Vecteur de statut)
@param(AContext Contexte d'exécution de la fonction externe)
@param(AInMsg Pointeur vers le message d'entrée)
@param(AOutMsg Pointeur vers le message de sortie)
}
procedure execute(AStatus: IStatus; AContext: IExternalContext;
AInMsg: Pointer; AOutMsg: Pointer); override;
end;
implementation
{ TSumArgsFunctionFactory }
procedure TSumArgsFunctionFactory.dispose;
begin
Destroy;
end;
function TSumArgsFunctionFactory.newItem(AStatus: IStatus;
AContext: IExternalContext; AMetadata: IRoutineMetadata): IExternalFunction;
begin
Result := TSumArgsFunction.Create();
end;
procedure TSumArgsFunctionFactory.setup(AStatus: IStatus;
AContext: IExternalContext; AMetadata: IRoutineMetadata;
AInBuilder, AOutBuilder: IMetadataBuilder);
begin
end;
{ TSumArgsFunction }
procedure TSumArgsFunction.dispose;
begin
Destroy;
end;
procedure TSumArgsFunction.execute(AStatus: IStatus; AContext: IExternalContext;
AInMsg, AOutMsg: Pointer);
var
xInput: PSumArgsInMsg;
xOutput: PSumArgsOutMsg;
begin
// convertir les pointeurs d'entrée et de sortie en pointeurs typés
xInput := PSumArgsInMsg(AInMsg);
xOutput := PSumArgsOutMsg(AOutMsg);
// par défaut, l'argument de sortie est NULL, il faut donc lui donner la valeur nullFlag
xOutput^.resultNull := True;
// si l'un des arguments est NULL, le résultat est NULL
// sinon, nous calculons la somme des arguments
with xInput^ do
begin
if not (n1Null or n2Null or n3Null) then
begin
xOutput^.result := n1 + n2 + n3;
// s'il y a un résultat, réinitialiser le drapeau NULL
xOutput^.resultNull := False;
end;
end;
end;
procedure TSumArgsFunction.getCharSet(AStatus: IStatus;
AContext: IExternalContext; AName: PAnsiChar; ANameSize: Cardinal);
begin
end;
end.
La classe de fonctions externe doit implémenter l’interface IUdrFunctionFactory
. Pour simplifier, nous héritons simplement de la classe IUdrFunctionFactoryImpl
. Chaque fonction externe a besoin de sa propre classe.Cependant, si les interfaces n’ont pas de spécificités pour créer une certaine fonction, alors vous pouvez écrire une interface générique en utilisant les generics. Nous donnerons plus loin un exemple de cette méthode.
La méthode dispose
est appelée lors de la destruction de la classe, au cours de laquelle nous devons libérer les ressources précédemment allouées. Dans ce cas, nous appelons simplement le destructeur.
La méthode de configuration est exécutée chaque fois qu’une fonction externe est chargée dans le cache de métadonnées. Elle permet d’effectuer diverses actions nécessaires avant de créer une instance d’une fonction, par exemple modifier le format des messages d’entrée et de sortie. Nous y reviendrons plus en détail ultérieurement.
La méthode newItem
est appelée pour instancier la fonction externe. Cette méthode reçoit un pointeur sur le vecteur d’état, le contexte de la fonction externe et les métadonnées de la fonction externe. Avec IRoutineMetadata
, vous pouvez obtenir le format du message d’entrée et de sortie, le corps de la fonction externe et d’autres métadonnées. Dans cette méthode, vous pouvez créer différentes instances d’une fonction externe en fonction de sa déclaration dans PSQL. Les métadonnées peuvent être transmises à l’instance de fonction externe créée si nécessaire. Dans notre cas, nous créons simplement une instance de la fonction externe TSumArgsFunction
.