
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