Фабрики
Вы уже сталкивались с фабриками ранее. Настало время рассмотреть ихболее подробно.
Фабрики предназначены для создания экземпляров процедур, функций илитриггеров. Класс фабрики должен быть наследником одного из интерфейсовIUdrProcedureFactory
, IUdrFunctionFactory
или IUdrTriggerFactory
взависимости от типа UDR. Их экземпляры должны быть зарегистрированы вкачестве точки входа UDR в функции firebird_udr_plugin
.
function firebird_udr_plugin(AStatus: IStatus; AUnloadFlagLocal: BooleanPtr;
AUdrPlugin: IUdrPlugin): BooleanPtr; cdecl;
begin
// регистрируем нашу функцию
AUdrPlugin.registerFunction(AStatus, 'sum_args',
TSumArgsFunctionFactory.Create());
// регистрируем нашу процедуру
AUdrPlugin.registerProcedure(AStatus, 'gen_rows', TGenRowsFactory.Create());
// регистрируем наш триггер
AUdrPlugin.registerTrigger(AStatus, 'test_trigger',
TMyTriggerFactory.Create());
theirUnloadFlag := AUnloadFlagLocal;
Result := @myUnloadFlag;
end;
В данном примере класс TSumArgsFunctionFactory
наследует интерфейсIUdrFunctionFactory
, TGenRowsFactory
наследует интерфейсIUdrProcedureFactory
, а TMyTriggerFactory
наследует интерфейсIUdrTriggerFactory
.
Экземпляры фабрик создаются и привязываются к точкам входа в моментпервой загрузки внешней процедуры, функции или триггера. Это происходитодин раз при создании каждого процесса Firebird. Таким образом, дляархитектуры SuperServer для всех соединений будет ровно один экземплярфабрики связанный с каждой точкой входа, для Classic это количествоэкземпляров будет умножено на количество соединений.
При написании классов фабрик вам необходимо реализовать методы setup
иnewItem
из интерфейсов IUdrProcedureFactory
, IUdrFunctionFactory
илиIUdrTriggerFactory
.
IUdrFunctionFactory = class(IDisposable)
const VERSION = 3;
procedure setup(status: IStatus; context: IExternalContext;
metadata: IRoutineMetadata; inBuilder: IMetadataBuilder;
outBuilder: IMetadataBuilder);
function newItem(status: IStatus; context: IExternalContext;
metadata: IRoutineMetadata): IExternalFunction;
end;
IUdrProcedureFactory = class(IDisposable)
const VERSION = 3;
procedure setup(status: IStatus; context: IExternalContext;
metadata: IRoutineMetadata; inBuilder: IMetadataBuilder;
outBuilder: IMetadataBuilder);
function newItem(status: IStatus; context: IExternalContext;
metadata: IRoutineMetadata): IExternalProcedure;
end;
IUdrTriggerFactory = class(IDisposable)
const VERSION = 3;
procedure setup(status: IStatus; context: IExternalContext;
metadata: IRoutineMetadata; fieldsBuilder: IMetadataBuilder);
function newItem(status: IStatus; context: IExternalContext;
metadata: IRoutineMetadata): IExternalTrigger;
end;
Кроме того, поскольку эти интерфейсы наследуют интерфейс IDisposable
, тонеобходимо так же реализовать метод dispose
. Это обозначает что Firebirdсам выгрузит фабрику, когда это будет необходимо. В методе dispose
необходимо разместить код, который освобождает ресурсы, при уничтоженииэкземпляра фабрики. Для упрощения реализации методов интерфейсов удобновоспользоваться классами IUdrProcedureFactoryImpl
,IUdrFunctionFactoryImpl
, IUdrTriggerFactoryImpl
. Рассмотрим каждыйиз методов более подробно.