Function factory
Now we need to write the factory and the function itself. They will be locatedin the SumArgsFunc module. Examples for writing procedures and triggers would bepresented later.
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
  // the structure to which the input message will be mapped
  TSumArgsInMsg = record
    n1: Integer;
    n1Null: WordBool;
    n2: Integer;
    n2Null: WordBool;
    n3: Integer;
    n3Null: WordBool;
  end;
  PSumArgsInMsg = ^TSumArgsInMsg;
  // the structure to which the output message will be mapped
  TSumArgsOutMsg = record
    result: Integer;
    resultNull: WordBool;
  end;
  PSumArgsOutMsg = ^TSumArgsOutMsg;
  // Factory for instantiating the external function TSumArgsFunction
  TSumArgsFunctionFactory = class(IUdrFunctionFactoryImpl)
    // Called when the factory is destroyed
    procedure dispose(); override;
    { Executed each time an external function is loaded into the metadata cache.
       Used to change the format of the input and output messages.
      @param(AStatus status vector)
      @param(AContext External function execution context)
      @param(AMetadata External Function Metadata)
      @param(AInBuilder Message builder for input metadata)
      @param(AOutBuilder Message builder for output metadata)
    }
    procedure setup(AStatus: IStatus; AContext: IExternalContext;
      AMetadata: IRoutineMetadata; AInBuilder: IMetadataBuilder;
      AOutBuilder: IMetadataBuilder); override;
    { Creating a new external function instance TSumArgsFunction
      @param(AStatus status vector)
      @param(AContext External function execution context)
      @param(AMetadata External Function Metadata)
      @returns(Экземпляр external function)
    }
    function newItem(AStatus: IStatus; AContext: IExternalContext;
      AMetadata: IRoutineMetadata): IExternalFunction; override;
  end;
  // External function TSumArgsFunction.
  TSumArgsFunction = class(IExternalFunctionImpl)
    // Called when the function instance is destroyed
    procedure dispose(); override;
    { This method is called just before execute and tells
       kernel our requested character set to exchange data internally
       this method. During this call, the context uses the character set
       obtained from ExternalEngine::getCharSet.
      @param(AStatus Status vector)
      @param(AContext External function execution context)
      @param(AName Character set name)
      @param(AName Character set name length)
    }
    procedure getCharSet(AStatus: IStatus; AContext: IExternalContext;
      AName: PAnsiChar; ANameSize: Cardinal); override;
    { Executing an external function
      @param(AStatus Status vector)
      @param(AContext External function execution context)
      @param(AInMsg Pointer to input message)
      @param(AOutMsg Pointer to output message)
    }
    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
  // convert pointers to input and output to typed ones
  xInput := PSumArgsInMsg(AInMsg);
  xOutput := PSumArgsOutMsg(AOutMsg);
  // by default, the output argument is NULL, so set it to nullFlag
  xOutput^.resultNull := True;
  // if one of the arguments is NULL, then the result is NULL
  // otherwise, we calculate the sum of the arguments
  with xInput^ do
  begin
    if not (n1Null or n2Null or n3Null) then
    begin
      xOutput^.result := n1 + n2 + n3;
      // if there is a result, then reset the NULL flag
      xOutput^.resultNull := False;
    end;
  end;
end;
procedure TSumArgsFunction.getCharSet(AStatus: IStatus;
  AContext: IExternalContext; AName: PAnsiChar; ANameSize: Cardinal);
begin
end;
end.The external function factory must implement the interfaceIUdrFunctionFactory. To simplify, we simply inherit the classIUdrFunctionFactoryImpl. Each external function needs its own factory.However, if factories do not have specifics for creating somefunction, then you can write a generic factory using generics. Later we will give anexample of how to do this.
The dispose method is called when the factory is destroyed, in which we must releasethe previously allocated resources. In this case, we simply call the destructor.
The setup method is executed each time an external function is loaded into the metadatacache. In it, you can do various actions that are necessary before creating an instanceof a function, for example, change the format for input and output messages. We’ll talkabout it in more detail later.
The newItem method is called to instantiate the external function. This method ispassed a pointer to the status vector, the context of the external function, and themetadata of the external function. With IRoutineMetadata you can get the format ofthe input and output message, the body of the external function, andother metadata. In this method, you can create different instances of an externalfunction depending on its declaration in PSQL. Metadata can be passed to the createdexternal function instance if needed. In our case, we simply create an instance of anexternal functionTSumArgsFunction.