Classes de procédures
La classe de la procédure externe doit implémenter l’interface IUdrProcedureFactory
. Pour simplifier, nous héritons simplement de la classe IUdrProcedureFactoryImpl
. Chaque procédure externe a besoin de sa propre classe. Cependant, si les classes n’ont pas de spécificités pour créer certaines procédures, vous pouvez écrire une classe générique en utilisant les génériques.Nous donnerons plus loin un exemple de cette méthode.
La méthode dispose
est appelée lorsque la classe est détruite, nous devons y libérer les ressources précédemment allouées. Dans ce cas, nous appelons simplement le Destructor.
La méthode setup
est exécutée à chaque fois que l’on charge la procédure externe dans les métadonnées du cache. Elle permet d’effectuer diverses actions nécessaires avant de créer une copie de la procédure, par exemple, un changement de format pour les messages d’entrée et de sortie. Nous en parlerons plus en détail ultérieurement.
La méthode Newitem
est utilisée pour créer une copie de la procédure externe. IN Cette méthode est transmise à l’indicateur de l’état du vecteur, du contexte de la procédure externe et des métadonnées de la procédure externe.En utilisant IRoutineMetadata
vous pouvez obtenir le format d’entrée et de sortie, le corps des fonctions externes et d’autres métadonnées. Cette méthode permet de créer plusieurs copies de la fonction externe en fonction de sa déclaration dans PSQL.Les métadonnées peuvent être transférées à la copie créée de la procédure externe si nécessaire. Dans notre cas, nous créons simplement une copie des procédures externes TSumArgsProcedure
.
La classe de la procédure, ainsi que la procédure même du module SumArgsProc
:
unit SumArgsProc;
{$IFDEF FPC}
{$MODE DELPHI}{$H+}
{$ENDIF}
interface
uses
Firebird;
{ **********************************************************
create procedure sp_sum_args (
n1 integer,
n2 integer,
n3 integer
) returns (result integer)
external name 'myudr!sum_args_proc'
engine udr;
********************************************************* }
type
// La structure dans laquelle le message d'entrée sera affiché
TSumArgsInMsg = record
n1: Integer;
n1Null: WordBool;
n2: Integer;
n2Null: WordBool;
n3: Integer;
n3Null: WordBool;
end;
PSumArgsInMsg = ^TSumArgsInMsg;
// La structure pour laquelle la sortie sera affichée
TSumArgsOutMsg = record
result: Integer;
resultNull: WordBool;
end;
PSumArgsOutMsg = ^TSumArgsOutMsg;
// Classe pour créer une copie de la procédure externe TSUMARGSPROCEDURE
TSumArgsProcedureFactory = class(IUdrProcedureFactoryImpl)
// Appelé lors de la destruction de la classe
procedure dispose(); override;
{Elle est effectuée à chaque fois lors du chargement de la procédure externe dans le cache des métadonnées.
Permet de modifier le format 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;
{ Creating a new copy of the external procedure TSumArgsProcedure
@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): IExternalProcedure; override;
end;
TSumArgsProcedure = class(IExternalProcedureImpl)
public
// Appelé lors de la destruction d'une copie de la procédure
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;
{ Procédure externe
@param(AStatus Vecteur de statut)
@param(AContext Contexte d'exécution de la fonction externe)
@param(AInMsg Pointeur du message (`IMessageMetadata`) d'entrée)
@param(AOutMsg Pointeur du message (`IMessageMetadata`) de sortie)
@returns(Ensemble de données pour une procédure sélective ou Nil pour les procédures)
}
function open(AStatus: IStatus; AContext: IExternalContext; AInMsg: Pointer;
AOutMsg: Pointer): IExternalResultSet; override;
end;
implementation
{ TSumArgsProcedureFactory }
procedure TSumArgsProcedureFactory.dispose;
begin
Destroy;
end;
function TSumArgsProcedureFactory.newItem(AStatus: IStatus;
AContext: IExternalContext; AMetadata: IRoutineMetadata): IExternalProcedure;
begin
Result := TSumArgsProcedure.create;
end;
procedure TSumArgsProcedureFactory.setup(AStatus: IStatus;
AContext: IExternalContext; AMetadata: IRoutineMetadata; AInBuilder,
AOutBuilder: IMetadataBuilder);
begin
end;
{ TSumArgsProcedure }
procedure TSumArgsProcedure.dispose;
begin
Destroy;
end;
procedure TSumArgsProcedure.getCharSet(AStatus: IStatus;
AContext: IExternalContext; AName: PAnsiChar; ANameSize: Cardinal);
begin
end;
function TSumArgsProcedure.open(AStatus: IStatus; AContext: IExternalContext;
AInMsg, AOutMsg: Pointer): IExternalResultSet;
var
xInput: PSumArgsInMsg;
xOutput: PSumArgsOutMsg;
begin
// Il n'est pas nécessaire de renvoyer de données pour que les procédures soient exécutées
Result := nil;
// 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 = NULL, et nous lui exposons donc le drapeau nullflag
xOutput^.resultNull := True;
// Si l'un des arguments est NULL, le résultat sera NULL.
// Dans le cas contraire, nous considérons le nombre d'arguments
with xInput^ do
begin
if not (n1Null or n2Null or n3Null) then
begin
xOutput^.result := n1 + n2 + n3;
// puisqu'il y a un résultat, laisser tomber le drapeau NULL
xOutput^.resultNull := False;
end;
end;
end;
end.