Factory of procedures
The factory of the external procedure should implement the interfaceIUdrProcedureFactory
. To simplify, we just inherit the classIUdrProcedureFactoryImpl
. Each external procedure needs its ownfactory. However, if factories have no specifics to create someprocedures, you can write a generalized factory using generics.Later we will give an example of how to do this.
The dispose
method is called when the factory is destroyed, in it we mustfree previously allocated resources. In this case, we simply callDestructor.
The setup
method is performed each time when loading the external procedure in cachemetadata. In it you can make various actions that are necessaryBefore creating a copy of the procedure, for example, a change in format forinput and output messages. Let’s talk about him in more detail later.
The Newitem
method is caused to create a copy of the external procedure. INThis method is transmitted to the indicator to the status of the vector, the context ofthe externalProcedures and metadata external procedure. Using IRoutineMetadata
you can get the input and output format, the body of the externalfunctions and other metadata. In this method you can create variouscopies of the external function depending on its ad in PSQL.Metadata can be transferred to the created copy of the external procedure ifit’s necessary. In our case, we simply create a copy of the externalTSumArgsProcedure
procedures.
The factory of the procedure, as well as the very procedure in the moduleSumArgsProc
.
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
// The structure of which the input message will be displayed
TSumArgsInMsg = record
n1: Integer;
n1Null: WordBool;
n2: Integer;
n2Null: WordBool;
n3: Integer;
n3Null: WordBool;
end;
PSumArgsInMsg = ^TSumArgsInMsg;
// The structure for which the output will be displayed
TSumArgsOutMsg = record
result: Integer;
resultNull: WordBool;
end;
PSumArgsOutMsg = ^TSumArgsOutMsg;
// Factory to create a copy of the external TSUMARGSPROCEDURE procedure
TSumArgsProcedureFactory = class(IUdrProcedureFactoryImpl)
// Called when the factory is destroyed
procedure dispose(); override;
{ It is performed each time when loading the external procedure in the cache of metadata
Used to change the input and output format.
@param(AStatus Status vector)
@param(AContext The context of the external procedure)
@param(AMetadata Metadata of the external procedure)
@param(AInBuilder Message builder for input metadata)
@param(AOutBuilder Message builder for weekend metadata)
}
procedure setup(AStatus: IStatus; AContext: IExternalContext;
AMetadata: IRoutineMetadata; AInBuilder: IMetadataBuilder;
AOutBuilder: IMetadataBuilder); override;
{ Creating a new copy of the external procedure TSumArgsProcedure
@param(AStatus Status vector)
@param(AContext The context of the external procedure)
@param(AMetadata Metadata of the external procedure)
@returns(Экземпляр external procedure)
}
function newItem(AStatus: IStatus; AContext: IExternalContext;
AMetadata: IRoutineMetadata): IExternalProcedure; override;
end;
TSumArgsProcedure = class(IExternalProcedureImpl)
public
// Called when destroying a copy of the procedure
procedure dispose(); override;
{ This method is called just before open and tells the kernel
our requested character set to communicate within this
method. During this call, the context uses the character set
obtained from ExternalEngine::getCharSet.
@param(AStatus Status vector)
@param(AContext The context of external function)
@param(AName The name of the set of characters)
@param(AName The length of the name of the set of characters)
}
procedure getCharSet(AStatus: IStatus; AContext: IExternalContext;
AName: PAnsiChar; ANameSize: Cardinal); override;
{ External procedure
@param(AStatus Status vector)
@param(AContext The context of external function)
@param(AInMsg Input message pointer)
@param(AOutMsg Output indicator)
@returns(Data set for a selective procedure or
Nil for the procedures)
}
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
// The set of data for the procedures performed is not necessary
Result := nil;
// We convert the signs to the input and access to the typized
xInput := PSumArgsInMsg(AInMsg);
xOutput := PSumArgsOutMsg(AOutMsg);
// By default, the output argument = NULL, and therefore we expose him nullflag
xOutput^.resultNull := True;
// If one of the arguments NULL means the result NULL
// Otherwise, we consider the amount of arguments
with xInput^ do
begin
if not (n1Null or n2Null or n3Null) then
begin
xOutput^.result := n1 + n2 + n3;
// since there is a result, then drop the NULL flag
xOutput^.resultNull := False;
end;
end;
end;
end.