Dnes jsem v rámci jednoho projektu potřeboval vyřešit docela komplikovanou analýzu a parsování řetězců na úrovni 64-bitového serveru FireBird 2.5 a při té příležitosti bych se rád se čtenáři Delphi.cz podělil o výsledky mého snažení, neb to sice není nic složitého, ale informace se shánějí obtížně a každý omyl končí pádem FireBirdu nebo přinejmenším další testy jsou podmíněny jeho restartem.
Delphi XE2, jak již zřejmě všichni víte, podporuje 64-bitovou platformu. Díky tomu lze snadno vytvořit UDF knihovnu jak pro 32-bitový, tak i 64-bitový server FireBird.
Vlastní knihovnu zahájíte vytvořením knihovny (File > New > Other). Poté v sekci „Delphi Project“ zvolíte „Dynamic-link Library“:

Získáte čistý projekt, který vypadá zhruba takto:

První, co musíte udělat, je vložení definice funkce zajišťující alokaci paměti kompatibilní s FireBirdem.
To se týká především vracení řetězců, ale rovněž pokud chcete vracet hodnoty odkazem a zároveň mít možnost vracet NULL.
Řádek vypadá takto:
function ib_util_malloc(l: integer): pointer; cdecl; external 'ib_util.dll';
Dalším krokem je vytvoření funkcí, které zajistí vlastní funkčnost. Zde je vhodné poznamenat, že při práci s řetězci je nutné mít na zřeteli kódování, ve kterém máte uložená data na serveru.
Rozhodně se nespoléhejte, že FireBird zajistí překlad kódových stránek.
Vlastní procedura pak může vypadat například takto:
1type
2
3 PInteger = ^Integer;
4
5function Priklad_UDF(
6 const Value1: PAnsiChar;
7 const Value2: PAnsiChar;
8 const Value3: PInteger
9): PAnsiChar; cdecl;
10
11var
12 data, data2: string;
13 s: TBytes;
14 e: TEncoding;
15 i, cnt: Integer;
16begin
17
18 if (Value1 = nil) or (Value2 = nil) or (Value3 = nil) then Exit(nil);
19
20
21 e := TEncoding.GetEncoding(1250);
22 try
23 try
24
25
26 SetLength(s, Length(Value1));
27 Move(Value1^, s[0], Length(s));
28 data := e.GetString(s);
29
30 SetLength(s, Length(Value2));
31 Move(Value2^, s[0], Length(s));
32 data2 := e.GetString(s);
33
34 for i := 1 to Value3^ do
35 data := data + ', ' + data2;
36
37 if (Length(data) > 2047) then SetLength(data, 2047);
38 except
39
40 Exit(nil);
41 end;
42
43 s := e.GetBytes(data);
44 cnt := Length(s);
45
46 Result := ib_util_malloc(cnt + 1);
47
48 Move(s[0], Result^, cnt);
49
50 Result[cnt] := #0;
51 finally
52
53 e.Free;
54 end;
55end;
56
57exports
58 Priklad_UDF name 'Priklad_UDF';
Povšimněte si především deklarace funkce. Všechny parametry jsou předávány odkazem a dále je uvedena volací konvence cdecl. Ještě musíme zveřejnit název, pod kterým FireBird funkci v knihovně najde (sekce exports). Zvolte si platformu (32 bitovou nebo 64 bitovou dle vašeho serveru) a proveďte kompilaci projektu.
Pokud vše skončí bez chyby, doporučuji knihovnu nakopírovat do složky UDF instalace FireBird. V opačném případě budeme muset upravit soubor firebird.conf a povolit vaše preferované umístění.
Aby FireBird o vaší funkci věděl, je nutné ji deklarovat pomocí následujícího příkazu:
DECLARE EXTERNAL FUNCTION PRIKLAD_UDF
CSTRING(250) null,
CSTRING(250) null,
INTEGER null
RETURNS CSTRING(2048) FREE_IT
ENTRY_POINT 'Priklad_UDF'
MODULE_NAME 'jméno knihovny bez .dll';
Použijte nějaký SQL nástroj, třeba výborný a bezplatný FlameRobin.
Klíčová slova NULL říkají, že funkce dokáže rozpoznávat hodnoty NULL, jinak by funkce dostávala předdefinované nulové hodnoty (tj. prázdný řetězec nebo nulu).
Klíčové slovo FREE_IT zase zajistí, že bude vrácený řetězec uvolněn z paměti, až jej FireBird nebude potřebovat.
Nyní spusťte SQL příkaz:
select PRIKLAD_UDF('abc', 'def', 4) from RDB$DATABASE;
Měli byste obdržet výsledek: abc, def, def, def, def.
Igor Gottwald