Getting and Using IMessageMetadata
Instances of objects that implement the IMessageMetadata
interface for input andoutput variables can be obtained from the IRoutineMetadata
interface. It is notpassed directly to an instance of a procedure, function, or trigger. This must be doneexplicitly in the factory of the appropriate type. For example:
// 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
@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 instance of the external function TSumArgsFunction
@param(AStatus Status vector)
@param(AContext External function execution context)
@param(AMetadata External function metadata)
@returns(External function instance)
}
function newItem(AStatus: IStatus; AContext: IExternalContext;
AMetadata: IRoutineMetadata): IExternalFunction; override;
end;
// External function TSumArgsFunction.
TSumArgsFunction = class(IExternalFunctionImpl)
private
FMetadata: IRoutineMetadata;
public
property Metadata: IRoutineMetadata read FMetadata write FMetadata;
public
// Called when the function instance is destroyed
procedure dispose(); override;
{ This method is called just before execute 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 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;
........................
{ TSumArgsFunctionFactory }
procedure TSumArgsFunctionFactory.dispose;
begin
Destroy;
end;
function TSumArgsFunctionFactory.newItem(AStatus: IStatus;
AContext: IExternalContext; AMetadata: IRoutineMetadata): IExternalFunction;
begin
Result := TSumArgsFunction.Create();
with Result as TSumArgsFunction do
begin
Metadata := AMetadata;
end;
end;
procedure TSumArgsFunctionFactory.setup(AStatus: IStatus;
AContext: IExternalContext; AMetadata: IRoutineMetadata;
AInBuilder, AOutBuilder: IMetadataBuilder);
begin
end;
Instances of IMessageMetadata
for input and output variables can be obtained usingthe getInputMetadata
and getOutputMetadata
methods from IRoutineMetadata
.Metadata for the fields of the table on which the trigger is written can be obtainedusing the getTriggerMetadata
method.
Important
|
Important
Please note that the lifecycle of |
To obtain the value of the corresponding input argument, we need to use addressarithmetic. To do this, we get the offset from IMessageMetadata
using the getOffset
method and add it to the buffer address for the input message. Then we reduce theresulting result to the corresponding typed pointer. Approximately the same scheme ofwork for obtaining null indicators of arguments, only the getNullOffset
method isused to obtain offsets.
........................
procedure TSumArgsFunction.execute(AStatus: IStatus; AContext: IExternalContext;
AInMsg, AOutMsg: Pointer);
var
n1, n2, n3: Integer;
n1Null, n2Null, n3Null: WordBool;
Result: Integer;
resultNull: WordBool;
xInputMetadata, xOutputMetadata: IMessageMetadata;
begin
xInputMetadata := FMetadata.getInputMetadata(AStatus);
xOutputMetadata := FMetadata.getOutputMetadata(AStatus);
try
// get the values of the input arguments by their offsets
n1 := PInteger(PByte(AInMsg) + xInputMetadata.getOffset(AStatus, 0))^;
n2 := PInteger(PByte(AInMsg) + xInputMetadata.getOffset(AStatus, 1))^;
n3 := PInteger(PByte(AInMsg) + xInputMetadata.getOffset(AStatus, 2))^;
// get values of null indicators of input arguments by their offsets
n1Null := PWordBool(PByte(AInMsg) +
xInputMetadata.getNullOffset(AStatus, 0))^;
n2Null := PWordBool(PByte(AInMsg) +
xInputMetadata.getNullOffset(AStatus, 1))^;
n3Null := PWordBool(PByte(AInMsg) +
xInputMetadata.getNullOffset(AStatus, 2))^;
//by default, the output argument is NULL, so we set it to nullFlag
resultNull := True;
Result := 0;
// if one of the arguments is NULL, then the result is NULL
// otherwise, we calculate the sum of the arguments
if not(n1Null or n2Null or n3Null) then
begin
Result := n1 + n2 + n3;
// once there is a result, then reset the NULL flag
resultNull := False;
end;
PWordBool(PByte(AInMsg) + xOutputMetadata.getNullOffset(AStatus, 0))^ :=
resultNull;
PInteger(PByte(AInMsg) + xOutputMetadata.getOffset(AStatus, 0))^ := Result;
finally
xInputMetadata.release;
xOutputMetadata.release;
end;
end;
Note
|
Comment
In the Connection and Transaction Context chapter,great example to work with various SQL types usinginterface |