Tech Tipp #7: Eine kleine UDF in InterBase

Posted by on in Programming

Frage: Ich vermisse die Funktion XYZ in InterBase. Warum gibt es die nicht?

Antwort: In der Tat gibt es einige Funktionen in InterBase (für die DML) in InterBase, die man vielleicht von anderen Datenbanken her kennt, die aber in InterBase nicht vorhanden sind.....

Aber es gibt eine (einfache!) Lösung: Man schreibt sich diese Funktion(en) selbst.

Ein gutes Video von meinem Kollegen Stephen Ball findet man dazu auch hier: https://www.youtube.com/watch?v=9bfaU5mdlaY

Daraus erstmal zwei wichtige Regeln:

  • Eine UDF sollte simple und schnell sein
  • Eine UDF sollte niemals den Status der Datenbank direkt manipulieren

Ein kleines Beispiel: In MS SQL Server/T-SQL gibt es einen ISNULL() oder auch im MySQL ein IFNULL(). Diese kann man zwar auch mit einem CASE umschreiben, macht es aber unter Umständen weniger gut lesbar:

Interbase Original:

SELECT
    (CASE
    WHEN column IS NULL
    THEN 'Alternative Value'
    ELSE column
    END) AS column
FROM
    table

Der Wunsch könnte sein:

SELECT
    ISNULL(column,'Alternative Value') AS column
FROM
    table

Sieht besser aus.... ist aber in InterBase nicht direkt möglich. Dafür gibt es UDFs (User Defined Functions).

Wie baut man das jetzt ein? Über eine DLL (32/64 Bit) bzw ein SO (Shared Object für Linux/Mac), die man in das passende InterBase Verzeichnis kopiert (hier: Windows, 64 Bit): C:\\Program Files\\Embarcadero\\InterBase\\UDF

Schritt für Schritt:

  • Delphi starten (oder C++Builder)
  • Datei | Neu | Weitere
  • Dynamische Link-Bibliothek
  • Date | Neu | Unit - Delphi
  • Hier, in der Unit, implementiert man dann die Funktionen im Interface- und Implementation-Teil der neuen Unit
  • Zielplattform wählen/ergänzen (32/64 Bit, Windows/Linux/Mac)
  • Export der Funktionen
  • DLL erzeugen

Quelltext der DLL  / Unit

library myUDFs;

uses
  System.SysUtils,
  System.Classes,
  UUDFFunctions in 'UUDFFunctions.pas';

{$R *.res}

begin
end.
unit UUDFFunctions;

interface

function IsNull(s1, s2: PChar): PChar; cdecl;

exports IsNull name 'IsNull';

implementation

function IsNull(s1, s2: PChar): PChar; cdecl;
begin
  if string(s1) = '' then // es gibt keinen NULL String
    result := s2
  else
    result := s1;
end;

end.

 

Wichtige Bemerkungen bei der Variablenübergabe:

  • Alle Variablen werden von InterBase als Referenzparameter übergeben
  • Ausnahme: PChar (Zeichenketten werden generell als PChar übergeben), die damit schon selbst eine Referenz darstellen.
    Also ein function irgendwas(var i:Integer;s:PChar)

Der Import mittels SQL-Befehl in iSQL / IBConsole:

DECLARE EXTERNAL FUNCTION IsNull
  CSTRING(256) CHARACTER SET NONE,
  CSTRING(256) CHARACTER SET NONE
RETURNS CSTRING(256) CHARACTER SET NONE
ENTRY_POINT 'IsNull' MODULE_NAME 'MyUDFs';

Bemerkungen zu den Funktionsnamen und der UDF selbst

  • Der Funktionsname und der Entry-Point können gleich heissen! Müssen aber nicht (hier heisst alles "IsNull")
  • IsNull heisst die Funktion in der Delphi-Unit, die als "IsNull" exportiert wird und auch dem InterBase-System wird diese als IsNull bekanntgegeben.
  • Der DLL-Name kann ohne den Zusatz ".DLL" angegeben werden
  • Die UDF sollte/kann im \UDF-Verzeichnis der InterBase-Installation liegen, kann aber auch in eine spezifiziertem Verzeichnis ("EXTERNAL_FUNCTION_DIRECTORY Parameter der IBCONFIG liegen)
  • Die DECLARE gilt immer nur für die verbundene Datenbank! Jede UDF muss in jeder Datenbank(Datei) deklariert werden
  • Die Funktionen sieht man auch in der IBConsole:

Anschliessend funktioniert auch ein IsNull in InterBase

SELECT isnull(A."SPALTE",'Nix drin') AS RESULT
FROM
"TABELLENNAME" A;

Die Möglichkeiten sind damit (fast) unendlich.....

Source: myUDFs



Comments

Check out more tips and tricks in this development video: