Die Anweisung CREATE FUNCTION definiert eine aufrufbare Funktion oder Prozedur.
Sie können auch die Anweisung CREATE PROCEDURE zum Definieren einer aufrufbaren Funktion oder Prozedur verwenden, die auch als Routine bezeichnet wird.
>>-CREATE--| Routinetyp |--Routinename--------------------------> >--(--| Parameterliste |--)--+-----------------+----------------> '-| Rückgabetyp |-' >--+-------------+--+--------------+--| Routinehauptteil |----->< '-| Sprache |-' '-| Ergebnis |-' Routinetyp |--+-FUNCTION--+------------------------------------------------| '-PROCEDURE-' Parameterliste .-,-----------------. V | |----+---------------+-+----------------------------------------| '-| Parameter |-' Parameter (1) |--+-IN-----+--Parametername--+-+----------+--Datentyp-+--------> +-OUT----+ | '-CONSTANT-' | '-INOUT--' | (2) | +-NAMESPACE--------------+ '-NAME-------------------' .-NULLABLE-. >--+----------+-------------------------------------------------| '-NOT NULL-' Rückgabetyp .-NULLABLE-. |--RETURNS--Datentyp--+----------+------------------------------| '-NOT NULL-' Sprache |--LANGUAGE--+-ESQL---------+-----------------------------------| | (3) | +-DATABASE-----+ +-.NET---------+ +-CLR----------+ '-JAVA---------' Ergebnis |--DYNAMIC RESULT SETS--ganze Zahl------------------------------| Routinehauptteil |--+-Anweisung-------------------------------------------------------------+--| '-EXTERNAL--NAME--Name_der_externen_Routine--+------------------------+-' +-.NetTypeInfo-----------+ '-JavaClassLoaderService-' .NetTypeInfo |--ASSEMBLY--Assemblierungsname---------------------------------> .------------------------------------------. V (4) | >--------+----------------------------------+-+-----------------| +-APPDOMAIN--Domänenname-----------+ +-VERSION--Version-----------------+ +-CULTURE--Kultur------------------+ '-PUBLICKEYTOKEN--Public-Key-Token-' JavaClassLoaderService |--CLASSLOADER--ClassLoaderConfigurableServiceName--------------|
Die Anweisungen CREATE FUNCTION und CREATE PROCEDURE definieren eine aufrufbare Funktion bzw. Prozedur, die auch als Routine bezeichnet wird.
In früheren Produktversionen wurden die Anweisungen CREATE FUNCTION und CREATE PROCEDURE unterschiedlich eingesetzt und hatten verschiedene Funktionen. Nachträgliche Erweiterungen haben zu den Unterschieden geführt, die zuvor in den Hinweisen 1 und 3 aufgeführt wurden.
Routinen sind bei der Erstellung wiederverwendbarer Codeblöcke hilfreich, die unabhängig mehrere Male ausgeführt werden können. Sie können in Form einer Reihe von ESQL-Anweisungen, als eine Java™- oder .NET-Methode oder als eine in einer Datenbank gespeicherte Prozedur implementiert werden. Aufgrund dieser Flexibilität gelten einige der Klauseln im Syntaxdiagramm nicht für alle Routinetypen bzw. sind nicht zulässig.
Jede Routine hat einen Namen, der innerhalb des Schemas, der die Routine angehört, eindeutig sein muss. Routinenamen können daher nicht überlappen. Wenn der Broker einen überlappenden Routinenamen findet, wird eine Ausnahme ausgegeben.
Geben Sie den Namen der Routine mit der Klausel Routinename und die Parameter der Routine mit der Klausel Parameterliste an. Wenn die LANGUAGE-Klausel ESQL angibt, muss die Routine unter Verwendung einer einzelnen ESQL-Anweisung implementiert werden. Diese Anweisung ist sehr nützlich, wenn es sich um eine Verbindungsanweisung handelt (BEGIN ... END), da sie dann so viele ESQL-Anweisungen, wie zur Ausübung ihrer Funktion erforderlich, enthalten kann.
Alternativ können Sie in der LANGUAGE-Klausel eine andere Sprache als ESQL angeben, anstatt einen ESQL-Hauptteil für die Routine bereitzustellen. Auf diese Weise sind Sie in der Lage, mit der EXTERNAL NAME-Klausel auf den tatsächlichen Hauptteil der Routine zu verweisen, wenn er extern zum Broker lokalisiert ist. Weitere Informationen zur Verwendung der EXTERNAL NAME-Klausel finden Sie unter Gespeicherte Prozeduren aufrufen und Eine Java-Routine aufrufen.
Routinen mit beliebigem LANGUAGE-Typ können die Parameter IN, OUT und INOUT haben. Der Aufrufende kann mehrere Werte in die Routine einstellen und mehrere aktualisierte Werte zurückempfangen. Diese zurückgegebenen Parameter kommen zu den für die Routine definierten RETURNS-Klauseln hinzu. Die RETURNS-Klausel definiert die Werte, die von der Routine an den Aufrufenden zurückgegeben werden.
Für in verschiedenen Sprachen implementierte Routinen gelten eigene Einschränkungen bezüglich der Datentypen, die eingestellt oder zurückgegeben werden können. Diese Einschränkungen sind weiter unten in diesem Abschnitt dokumentiert. Der Datentyp des zurückgegebenen Werts muss mit dem Datentyp des Werts übereinstimmen, der laut Definition von der Routine zurückgegeben werden soll. Wenn eine Routine laut Definition einen Rückgabewert haben soll, kann ihn der Aufrufende der Routine nicht ignorieren. Der Abschnitt CALL-Anweisung enthält weitere Informationen hierzu.
Bezüglich der Sprache oder des Routinetyps muss die Methode des Aufrufens der Routine der Methode ihrer Deklaration entsprechen. Wenn die Routine eine RETURNS-Klausel besitzt, verwenden Sie entweder die Aufrufsyntax FUNCTION oder eine CALL-Anweisung mit einer INTO-Klausel. Umgekehrt gilt: Hat eine Routine keine RETURNS-Klausel, muss eine CALL-Anweisung ohne INTO-Klausel verwendet werden.
Hat die Routine den Typ FUNCTION (Funktion), ist der Richtungsanzeiger (IN, OUT, INOUT) für jeden Parameter optional. Wir empfehlen jedoch dringend, aus Dokumentationsgründen einen Richtungsanzeiger für alle neuen Routinen mit beliebigem Typ festzulegen.
ESQL-Variablen, die als CONSTANT deklariert sind (oder Verweise auf als CONSTANT deklarierte Variablen) dürfen nicht die Richtung OUT oder INOUT haben.
ESQL-Routinen sind in ESQL geschrieben und ihre LANGUAGE-Klausel gibt die Sprache ESQL an. Als Hauptteil einer ESQL-Routine wird gewöhnlich eine Verbindungsanweisung in der Form BEGIN … END verwendet, die mehrere Anweisungen zur Verarbeitung der Parameter enthält, die an die Routine übermittelt wurden.
CREATE PROCEDURE swapParms (
IN parm1 CHARACTER,
OUT parm2 CHARACTER,
INOUT parm3 CHARACTER )
BEGIN
SET parm2 = parm3;
SET parm3 = parm1;
END;
Diese Beispielprozedur zeigt die rekursive Verwendung einer ESQL-Routine. Sie analysiert die Syntax einer Baumstruktur an sämtlichen Stellen am und unterhalb des angegebenen Ausgangspunkts und dokumentiert anschließend das Ergebnis:
SET OutputRoot.MQMD = InputRoot.MQMD;
DECLARE answer CHARACTER;
SET answer = '';
CALL navigate(InputRoot.XMLNS, answer);
SET OutputRoot.XMLNS.Data.FieldNames = answer;
CREATE PROCEDURE navigate (IN root REFERENCE, INOUT answer CHARACTER)
BEGIN
SET answer = answer || 'Reached Field... Type:' || CAST(FIELDTYPE(root) AS CHAR)||
': Name:' || FIELDNAME(root) || ': Value :' || root || ': ';
DECLARE cursor REFERENCE TO root;
MOVE cursor FIRSTCHILD;
IF LASTMOVE(cursor) THEN
SET answer = answer || 'Field has children... drilling down ';
ELSE
SET answer = answer || 'Listing siblings... ';
END IF;
WHILE LASTMOVE(cursor) DO
CALL navigate(cursor, answer);
MOVE cursor NEXTSIBLING;
END WHILE;
SET answer = answer || 'Finished siblings... Popping up ';
END;
Lautet die Eingabenachricht wie folgt:
<Person>
<Name>John Smith</Name>
<Salary period='monthly' taxable='yes'>-1200</Salary>
</Person>
dann erstellt die Prozedur die folgende Ausgabe, die manuell formatiert wurde:
Reached Field... Type:16777232: Name:XML: Value :: Field has children... drilling down
Reached Field... Type:16777216: Name:Person: Value :: Field has children... drilling down
Reached Field... Type:16777216: Name:Name:
Value :John Smith: Field has children... drilling down
Reached Field... Type:33554432: Name::
Value :John Smith: Listing siblings... Finished siblings... Popping up
Finished siblings... Popping up
Reached Field... Type:16777216: Name:Salary:
Value :-1200: Field has children... drilling down
Reached Field... Type:50331648: Name:period:
Value :monthly: Listing siblings... Finished siblings... Popping up
Reached Field... Type:50331648: Name:taxable:
Value :yes: Listing siblings... Finished siblings... Popping up
Reached Field... Type:33554432: Name::
Value :-1200: Listing siblings... Finished siblings... Popping up
Finished siblings... Popping up
Finished siblings... Popping up
Finished siblings... Popping up
Eine .NET-Routine wird als .NET-Methode implementiert und hat die LANGUAGE-Klausel .NET oder CLR. Bei .NET-Routinen muss der Name_der_externen_Routine den Klassennamen und den Namen der aufzurufenden .NET-Methode enthalten. Geben Sie den Namen_der_externen_Routine wie im folgenden Beispiel an:
>>--"-- Klassenname---.---Methodenname--"--------------><
Dabei
steht Name_Klasse für die Klasse, die die Methode enthält, und
Name_der_Methode für die Methode, die aufgerufen werden soll. Wenn die Klasse
Teil eines Namespace oder eine verschachtelte Klasse ist, muss die Klassen-ID die Namen aller
Namespaces und verschachtelten Klassen enthalten, z. B.
"IBM.Broker.test.MyOuterClass.MyNestedClass.MyMethod"Der Broker durchsucht das GAC und die AppDomain-Basisposition nach der .NET-Klasse.
Jede .NET-Methode, die Sie aufrufen möchten, muss eine öffentliche statische Methode sein. Darüber hinaus müssen alle Parameter in Zuordnungstabellen für Datentypen von ESQL nach .NET aufgelistet sein. Wenn die Methode einen Rückgabetyp besitzt, muss dieser außerdem in der IN-Datentypzuordnungstabelle aufgelistet sein.
CREATE PROCEDURE Swap (
IN a INT NOT NULL,
OUT b INT NOT NULL,
INOUT c INT NOT NULL ) RETURNS CHARACTER NOT NULL
LANGUAGE .NET
EXTERNAL NAME "FunctionTests.SwapString"
ASSEMBLY "C:\coding\test projects\MyAssembly"
APPDOMAIN "MyDomain";
CALL Swap( intVar1, intVar2, intVar3 ) INTO ReturnVar;
-- oder
SET ReturnVar = Swap ( intVar1, intVar2, intVar3);
Definiert eine Prozedur, die eine .NET-Methode, die keinen Rückgabewert besitzt, mit drei nullfähigen Parametern mit unterschiedlichen Anweisungen darstellt.
CREATE PROCEDURE SwapNullable (
IN a INTEGER NULLABLE,
OUT b INTEGER NULLABLE,
INOUT c INTEGER NULLABLE )
LANGUAGE CLR
EXTERNAL NAME "FunctionTests.SwapStringNullable"
ASSEMBLY "MyAssembly2"
APPDOMAIN "MyDomain";
CALL SwapNullable(intVar1, intVar2, intVar3);
C#
public class FunctionTests
{
public static string Swap(int pIn, out int pOut, ref int pInout)
{
pOut = pInout;
pInout = pIn;
return "Finished";
}
public static void SwapNullable(long? pIn, out long? pOut, ref long? pInout)
{
pOut = pInout;
pInout = pIn;
}
}
VB
Public Class FunctionTests
Shared Function Swap(ByVal pIn As Integer, <Out()> ByRef pOut As Integer, ByRef pInout As Integer) As String
pOut = pInout
pInout = pIn
Return "Finished"
End Function
Shared Sub SwapNullable(ByVal pIn As Long?, ByRef pOut As Long?, ByRef pInout As Long?)
pOut = pInout
pInout = pIn
End Sub
End Class
F#
module FunctionTests
let Swap( pIn : int, [<Out>] pOut : byref<int> , pInOut : byref<int> ) = (
pOut <- pInout
pInout <- pIn
let temp = "Finished"
temp
)
let SwapNullable( pIn : Nullable<int64>, [<Out>] pOut : byref<Nullable<int64>> , pInOut : byref<Nullable<int64>> ) = (
pOut <- pInout
pInout)
)
C++ / CLi
public ref class FunctionTests
{
public:
static String^ Swap(int pIn, [Out] int% pOut, int% pInout)
{
pOut = pInout;
pInout = pIn;
String^ temp = "Finished";
return temp;
}
static void SwapNullable(Nullable<long long> pIn, [Out] Nullable<long long>% pOut, Nullable<long long>% pInout)
{
pOut = pInout;
pInout = pIn;
}
}
>>--"-- Klassenname---.---Methodenname--"--------------><
dabei steht Klassenname für die Klasse, die die Methode enthält, und Methodenname gibt die Methode an, die aufgerufen werden soll. Wenn die
Klasse Teil eines Pakets ist, muss der Teil mit der Klassen-ID das komplette Paketpräfix
einschließen, z. B. "com.ibm.broker.test.MyClass.myMethod". Für die Suche nach der Java-Klasse verwendet der Broker die in Implementierung von Java-Klassen beschriebene Suchmethode.
public static <Rückgabetyp> <Methodenname> (< 0 - N Parameter>)
Dabei muss der <Rückgabetyp> in der Liste der Java-Datentypen IN in der Tabelle in der Zuordnung von ESQL zum Java-Datentyp enthalten sein (ausgenommen REFERENCE, da dieser Typ als Rückgabewert unzulässig ist) oder dem Java-Datentyp 'void' entsprechen. Die Parameterdatentypen müssen ebenfalls aus der Tabelle der Zuordnung von ESQL zum Java-Datentyp stammen. Zudem darf die Java-Methode keine exception throws-Klausel (Ausnahmeauslöser) in ihrer Signatur haben.
Die Klausel im Abschnitt 'JavaClassLoader' gilt nur für LANGUAGE JAVA-Routinen. CLASSLOADER ist eine optionale Klausel. Wenn Sie diese Klausel nicht angeben, wird die Java-Klasse vom Klassenladeprogramm 'EGShared' geladen. Sie finden weitere Informationen hierzu in den Abschnitten Klassen für JavaCompute-Knoten laden und Konfigurierbarer JavaClassLoader-Service.
Sie können in der Java-Methode die API des benutzerdefinierten Java-Knotens verwenden, sofern Sie die in Einschränkungen bei Java-Routinen dokumentierten Einschränkungen beachten. Weitere Informationen zur Verwendung der Java-API finden Sie im Abschnitt Benutzerdefinierten Java-Knoten kompilieren.
Diese Routine enthält drei Parameter unterschiedlicher Richtungen und gibt eine Ganzzahl zurück, die dem Java-Rückgabetyp java.lang.Long entspricht.
CREATE FUNCTION myProc1( IN P1 INTEGER, OUT P2 INTEGER, INOUT P3 INTEGER )
RETURNS INTEGER
LANGUAGE JAVA
EXTERNAL NAME "com.ibm.broker.test.MyClass.myMethod1";
Sie können für den Aufruf von myProc1 folgenden ESQL-Ausdruck verwenden:
CALL myProc1( intVar1, intVar2, intVar3) INTO intReturnVar3;
-- oder
SET intReturnVar3 = myProc1( intVar1, intVar2, intVar3);
Diese Routine enthält drei Parameter unterschiedlicher Richtungen und hat den Java-Rückgabetyp void (typenlos).
CREATE PROCEDURE myProc2( IN P1 INTEGER, OUT P2 INTEGER, INOUT P3 INTEGER )
LANGUAGE JAVA
nEXTERNAL NAME "com.ibm.broker.test.MyClass.myMethod2";
Sie müssen für den Aufruf von myProc2 folgenden ESQL-Ausdruck verwenden:
CALL myProc2(intVar1, intVar2, intVar3);
Die folgende Java-Klasse bietet eine Methode für jedes der Java-Beispiele:
package com.ibm.broker.test;
class MyClass {
public static Long myMethod1( Long P1, Long[] P2 Long[] P3) { ... }
public static void myMethod2( Long P2, Long[] P2 Long[] P3) { ... }
/* Wenn eine dieser Methoden aufgerufen wird:
P1 kann den Wert NULL haben oder nicht (abhängig vom Wert von intVar1).
P2[0] hat stets den Wert NULL (unabhängig vom Wert von intVar2).
P3[0] kann den Wert NULL haben oder nicht (abhängig vom Wert von intVar3).
Alles entspricht der Verwendung von LANGUAGE ESQL-Routinen.
Wenn diese Methoden Werte zurückgeben:
intVar1 ist unverändert
intVar2 kann immer noch den Wert NULL oder einen anderen Wert haben
intVar3 kann denselben Wert oder einen anderen Wert haben
Alles entspricht der Verwendung von LANGUAGE ESQL-Routinen.
Wenn myMethod1 Folgendes zurückgibt: intReturnVar3 ist entweder NULL (wenn die
Methode NULL zurückgibt) oder enthält den Wert, den die
Methode zurückgegeben hat.
*/
}
CREATE FUNCTION myMethod1 ( IN P1 INTEGER, IN P2 INTEGER )
RETURNS INTEGER
LANGUAGE JAVA
EXTERNAL NAME "com.ibm.broker.test.MyClass.myMethod1"
CLASSLOADER "myClassLoader";
ESQL-Datentypen 1 | Java IN-Datentypen | Java INOUT- und OUT-Datentypen |
---|---|---|
INTEGER, INT | java.lang.Long | java.lang.Long [] |
FLOAT | java.lang.Double | java.lang.Double[] |
DECIMAL | java.math.BigDecimal | java.math.BigDecimal[] |
CHARACTER, CHAR | java.lang.String | java.lang.String[] |
BLOB | byte[] | byte[][] |
BIT | java.util.BitSet | java.util.BitSet[] |
DATE | com.ibm.broker.plugin.MbDate | com.ibm.broker.plugin.MbDate[] |
TIME 2 | com.ibm.broker.plugin.MbTime | com.ibm.broker.plugin.MbTime[] |
GMTTIME 2 | com.ibm.broker.plugin.MbTime | com.ibm.broker.plugin.MbTime[] |
TIMESTAMP 2 | com.ibm.broker.plugin.MbTimestamp | com.ibm.broker.plugin.MbTimestamp[] |
GMTTIMESTAMP 2 | com.ibm.broker.plugin.MbTimestamp | com.ibm.broker.plugin.MbTimestamp[] |
INTERVAL | Wird nicht unterstützt | Wird nicht unterstützt |
BOOLEAN | java.lang.Boolean | java.lang.Boolean[] |
REFERENCE (auf eine Nachrichtenbaumstruktur) 3 4 5 6 | com.ibm.broker.plugin.MbElement | com.ibm.broker.plugin.MbElement[] (Wird für INOUT unterstützt, nicht für OUT) |
ROW | Wird nicht unterstützt | Wird nicht unterstützt |
LIST | Wird nicht unterstützt | Wird nicht unterstützt |
Wenn beispielsweise ein ESQL-Verweis auf OutputRoot.XML.Test als INOUT-MbElement an eine Java-Methode übergeben wird, bei Rückkehr des Aufrufs aber ein anderes MbElement an ESQL zurückgegeben wird, muss dieses andere Element ebenfalls auf eine Position innerhalb der OutputRoot-Baumstruktur verweisen.
Ein Verweis auf eine Skalarvariable kann im Aufruf einer Java-Methode verwendet wurde, vorausgesetzt, der Datentyp der Variablen, auf die verwiesen wird, entspricht dem entsprechenden Datentyp in der Java-Programmsignatur.
Innerhalb der Methode können Threads erstellt werden. Erstellte Threads dürfen die Java-APIs jedoch nicht verwenden, und die Steuerung muss wieder an den Broker zurückgegeben werden.
Alle Einschränkungen hinsichtlich der Verwendung der Java-API gelten auch für Java-Methoden, die aus ESQL aufgerufen werden.
Die effizienteste und flexibelste Methode zur Implementierung auf dem Broker besteht darin, die JAR-Datei zur BAR-Datei hinzuzufügen. Sie können diese Aufgabe manuell oder automatisch über das WebSphere Message Broker Toolkit ausführen.
Wenn das WebSphere Message Broker Toolkit die korrekte Java-Klasse in einem geöffneten referenzierten Java-Projekt im Arbeitsbereich findet, wird die Java-Klasse automatisch in eine JAR-Datei kompiliert und zur BAR-Datei hinzugefügt. Diese Prozedur ist mit der Prozedur zur Implementierung eines JavaCompute-Knotens in einer JAR-Datei identisch (siehe Klassenladen für benutzerdefinierte Knoten).
Wenn Sie eine JAR-Datei über das WebSphere Message Broker Toolkit implementieren, lädt der erneut implementierte Fluss die in der BAR-Datei enthaltene JAR-Datei.
Ebenso werden die Dateien erneut geladen, wenn der Nachrichtenfluss, der auf eine Java-Klasse verweist, gestoppt und erneut gestartet wird. Stellen Sie sicher, dass Sie alle Flüsse, die auf die zu aktualisierende JAR-Datei verweisen, stoppen und neu starten (bzw. erneut implementieren). Auf diese Weise verhindern Sie, dass einige Flüsse mit der alten Version der JAR-Datei und andere Flüsse mit der neuen Version ausgeführt werden.
Mit dem WebSphere Message Broker Toolkit werden nur JAR-Dateien, nicht jedoch eigenständige Java-Klassendateien implementiert.
Diese Aktion muss manuell durchgeführt werden, das WebSphere Message Broker Toolkit kann hierfür nicht verwendet werden.
Bei diesem Verfahren werden bei einer erneuten Implementierung des Nachrichtenflusses die Java-Klassen, auf die verwiesen wird, nicht erneut geladen, und der Nachrichtenfluss wird nicht gestoppt und neu gestartet. In diesem Fall können die Klassen nur neu geladen werden, indem Sie den Broker stoppen und neu starten.
Damit der Broker eine Java-Klasse finden kann, müssen Sie sicherstellen, dass sie sich in einem der folgenden Verzeichnisse befindet. Wenn der Broker die angegebene Klasse nicht finden kann, wird eine Ausnahme generiert.
Zwar stehen Ihnen bei der Implementierung der JAR-Datei die zuvor genannten Möglichkeiten zur Verfügung, die Verwendung des WebSphere Message Broker Toolkits bei der Implementierung der BAR-Datei bietet jedoch die größte Flexibilität bei der erneuten Implementierung der JAR-Datei.
Datenbankroutinen werden von der Funktion CREATE FUNCTION nicht unterstützt. Verwenden Sie CREATE PROCEDURE zum Definieren einer Datenbankroutine.