Dann los: UDRs sind verpackt in eine oder mehrere libs (.dll oder .so etc). Die Beispiel-lib hab ich PascalUDR genannt. Deren PascalUDR.dpr sieht so aus:
Code: Alles auswählen
library PascalUDR;
uses
System.SysUtils,
System.Classes,
FBUDRController,
UdrReadText in 'UdrReadText.pas';
{$R *.res}
exports firebird_udr_plugin;
begin
with FBUDRControllerOptions do
begin
ModuleName := 'PascalUDR';
AllowConfigFileOverrides := true;
LogFileNameTemplate := '$UDRDIR$MODULE.log';
LogOptions := [loLogFunctions, loLogProcedures, loLogTriggers, loDetails];
ThreadSafeLogging := True;
end;
end.
Oben mit UdrReadText die unit der ersten Beispiel-UDR.
Die ControllerOptions steuern hauptsächlich das Logging, kann man auch ausmachen, wenn man es nicht braucht, am Anfang ist es ganz interessant.
Die unit UDRReadText.pas beherbergt die UDR read_text (die unit könnte natürlich auch mehrere UDRs definieren), die zeilenweise aus einer Textdatei liest, die mit path angegeben wird. Die Zeilen werden satzweise zurückgegeben. read_text ist vom Typ TFBUDRSelectProcedure, da sie mehr als einen Satz zurückgeben soll. Es gibt noch die Typen TFBUDRExecuteProcedure und TFBUDRFunction und TFBUDRTrigger.
Als TFBUDRSelectProcedure muss read_txt die drei Methoden open, fetch und close mit Inhalt füllen.
open - Initialisierung
fetch - Daten eines Satzes bereitstellen
close - aufräumen - im Beispiel leer
Oben im Kopf der unit steht auskommentiert die Deklaration, mit der diese UDR der Datenbank bekannt gemacht werden muss.
Code: Alles auswählen
unit UdrReadText;
{
create or alter procedure read_text (
path varchar(300) not null
) returns (
text varchar(3000)
)
external name 'pascaludr!read_text'
engine udr;
}
interface
uses Classes, SysUtils, IB, FBUDRController, FBUDRIntf;
type
TReadTextFile = class(TFBUDRSelectProcedure)
private
FTextFile: TStreamReader;
public
procedure open(context: IFBUDRExternalContext; ProcMetadata: IFBUDRProcMetadata; InputParams: IFBUDRInputParams); override;
function fetch(OutputData: IFBUDROutputData): boolean; override;
procedure close; override;
end;
implementation
procedure TReadTextFile.open(context: IFBUDRExternalContext; ProcMetadata: IFBUDRProcMetadata; InputParams: IFBUDRInputParams);
begin
FTextFile := TStreamReader.Create(InputParams.ByName('path').AsString, TEncoding.ANSI);
end;
function TReadTextFile.fetch(OutputData: IFBUDROutputData): boolean;
begin
Result := not FTextFile.EndOfStream;
if Result then
OutputData.ByName('text').AsString := FTextFile.ReadLine;
end;
procedure TReadTextFile.close;
begin
if FTextFile <> nil then
FTextFile.Free;
FTextFile := nil;
end;
initialization
FBRegisterUDRProcedure('read_text', TReadTextFile);
end.
Ich benutze zur Zeit Delphi 10.4 zur Übersetzung, aber fbintf ist eigentlich sogar eher für Freepascal geschrieben, damit sollte es auch gehen.
Die übersetzte lib PascalUDR.dll kopiert man am einfachsten ins Verzeichnis ...\Firebird_4\plugins\udr, dann muss man dort nichts weiter konfigurieren. Anschließend in der Zieldatenbank die UDR registrieren mittels der auskommentierten Deklaration oben im unit-Kopf:
Code: Alles auswählen
create or alter procedure read_text (
path varchar(300) not null
) returns (
text varchar(3000)
)
external name 'pascaludr!read_text'
engine udr;
Aufruf dann zb
Code: Alles auswählen
select * from read_text('C:\Programme\Firebird\Firebird_4\firebird.log')
und wenn alles geklappt hat, sieht man das firebird.log tabellarisch im Abfrageergebnis.
und mit
Code: Alles auswählen
select count(*) abschuss
from read_text('C:\Programme\Firebird\Firebird_4\firebird.log')
where text containing 'abnormally'
sieht man die Anzahl der Serverabschüsse gemäß log
Das Beispiel ist bewusst einfach gehalten, um erstmal einen Überblick zu bekommen, wie das prinzipiell läuft bei UDRs. Hier ist noch nichts mit Attachments, Transaktionen, Blobs usw gemacht, das kommt in späteren Beispielen.
Grüße, Volker