64-bitové UDF v RAD Studio XE2 pro FireBird

vložil Igor Gottwald 2. prosince 2011 00:53

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“:

UDF Delphi

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

Blank UDF Firebird

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  // pokud je některá hodnota NULL, vracím NULL
   18  if (Value1 = nil) or (Value2 = nil) or (Value3 = nil) then Exit(nil);
   19  // v mém případě používám kódování WIN1250, pro UTF-8 použijte TEncoding.UTF8 
   20  //a na konci jej neuvolňujte!
   21  e := TEncoding.GetEncoding(1250);
   22  try
   23    try
   24 // zde provedu nějaké operace, pokud možno užitečnější než jsou v tomto příkladu :-)
   25      // načtu první řetězec
   26      SetLength(s, Length(Value1));
   27      Move(Value1^, s[0], Length(s));
   28      data := e.GetString(s);
   29      // načtu druhý řetězec
   30      SetLength(s, Length(Value2));
   31      Move(Value2^, s[0], Length(s));
   32      data2 := e.GetString(s);
   33      // k prvnímu textu přidám druhý text tolikrát, kolikrát určuje třetí parametr
   34      for i := 1 to Value3^ do
   35        data := data + ', ' + data2;
   36      // výsledek omezím na velikost, kterou později deklaruji ve FireBirdu
   37      if (Length(data) > 2047) then SetLength(data, 2047);
   38    except
   39      // výjimky je nutné odchytit, jinak se z toho FireBird nevzpamatuje
   40      Exit(nil);
   41    end;
   42  // výsledek v podobě textu převedu zpět do požadovaného kódování (vytvořím pole bytů)
   43    s := e.GetBytes(data);
   44    cnt := Length(s);
   45    // alokuji dostatečně velký buffer pro vrácení výsledku pomocí funkce FireBirdu
   46    Result := ib_util_malloc(cnt + 1);
   47    // zkopíruji výsledek do prostoru, který bude přístupný FireBirdu
   48    Move(s[0], Result^, cnt);
   49    // nastavím poslední byte na 0 pro ukončení řetězce
   50    Result[cnt] := #0;
   51  finally
   52    // nezapomenu uvolnit objekt kódování, pokud jsem nepoužil některý předdefinovaný
   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


Nabízíme Delphi školení a konzultace na různá témata, primárně ve Vaší firmě.

Tagy: , ,

Návody

Komentáře

12.4.2012 7:44:03 #

JK

Dobrý den,
Mám otázku.
Může se v udf knihovně Pchar přetypovat na standardní string a poté zase zpět?
Je s ním lepší práce, ale nevím, jesli by to nevadilo. Můžete mi to přiblížit.

Díky JK.

JK

Komentování ukončeno

Naše nabídka

Partial English version.

MVP
Ing. Radek Červinka - Embarcadero MVP
profil na linkedin, Twitter:@delphicz

Nabízím placené poradenství a konzultace v oblasti programování a vývoje SW.
Dále nabízíme i vývoj speciálního software na zakázku.

Neváhejte nás kontaktovat (i ohledně reklamy nebo burzy práce).

Pokud chcete podpořit tento server libovolnou částkou, můžete použít PayPal. Moc děkuji.

Delphi Certified Developer

O Delphi.cz

Delphi je jediný moderní RAD nástroj podporující tvorbu nativních aplikací pro platformu Win32, Win64 , Mac OSX a na iPhone a Android (s výhledem na další platformy díky FireMonkey) na současném trhu (včetně Windows 8.1).

V současnosti je světová komunita přes dva miliónů vývojářů.

Delphi.cz je nezávislý portál pro uživatele Delphi. Portál není koncipován pro úplné začátečníky, i když i ti se zde nebudou nudit, ale spíše na programátory, kteří již něco znají a chtějí své znalosti dále rozvíjet a sledovat novinky.

Anketa

Poslední komentáře

Comment RSS