A instrução CREATE FUNCTION define uma função ou procedimento que pode ser chamado.
Você também pode utilizar a instrução CREATE PROCEDURE para definir uma função ou procedimento que pode ser chamado, também conhecido como rotina.
>>-CREATE--| RoutineType |--RoutineName-------------------------> >--(--| ParameterList |--)--+----------------+------------------> '-| ReturnType |-' >--+--------------+--+---------------+--| RoutineBody |-------->< '-| Language |-' '-| ResultSet |-' RoutineType |--+-FUNCTION--+------------------------------------------------| '-PROCEDURE-' ParameterList .-,-----------------. V | |----+---------------+-+----------------------------------------| '-| Parâmetro |-' Parâmetro (1) |--+-IN-----+--ParameterName--+-+----------+--DataType-+--------> +-OUT----+ | '-CONSTANT-' | '-INOUT--' | (2) | +-NAMESPACE--------------+ '-NAME-------------------' .-NULLABLE-. >--+----------+-------------------------------------------------| '-NOT NULL-' ReturnType .-NULLABLE-. |--RETURNS--DataType--+----------+------------------------------| '-NOT NULL-' Language |--LANGUAGE--+-ESQL---------+-----------------------------------| | (3) | +-DATABASE-----+ +-.NET---------+ +-CLR----------+ '-JAVA---------' ResultSet |--DYNAMIC RESULT SETS--integer---------------------------------| RoutineBody |--+-Statement-------------------------------------------------------+--| '-EXTERNAL--NAME--ExternalRoutineName--+------------------------+-' +-.NetTypeInfo-----------+ '-JavaClassLoaderService-' .NetTypeInfo |--ASSEMBLY--AssemblyName---------------------------------------> .----------------------------------------. V (4) | >--------+--------------------------------+-+-------------------| +-APPDOMAIN--DomainName----------+ +-VERSION--Versão----------------+ +-CULTURE--Cultura---------------+ '-PUBLICKEYTOKEN--PublicKeyToken-' JavaClassLoaderService |--CLASSLOADER--ClassLoaderConfigurableServiceName--------------|
As instruções CREATE FUNCTION e CREATE PROCEDURE definem uma função ou um procedimento que pode ser chamado, também conhecido como rotina.
Em versões anteriores deste produto, CREATE FUNCTION e CREATE PROCEDURE tinham diferentes utilizações e recursos. Aprimoramentos subseqüentes resultaram nas diferenças listadas anteriormente nas notas 1 e 3.
As rotinas são úteis para criar blocos reutilizáveis de código que podem ser executados independentemente várias vezes. É possível implementá-las como uma série de instruções ESQL, um método Java™, um método .NET ou um procedimento armazenado do banco de dados. Essa flexibilidade significa que algumas das cláusulas no diagrama de sintaxe não são aplicáveis (ou permitidas) para todos os tipos de rotina.
Cada rotina possui um nome, que deve ser exclusivo no esquema ao qual ela pertence. Os nomes de rotina, portanto, não podem ser sobrecarregados; se o intermediário detectar que um nome de rotina foi sobrecarregado, ele exibirá uma exceção.
Especifique o nome da rotina usando a cláusula RoutineName e seus parâmetros usando a cláusula ParameterList. Se a cláusula LANGUAGE especificar ESQL, implemente a rotina usando uma única instrução ESQL. Essa instrução será mais útil se for uma instrução composta (BEGIN ... END), uma vez que pode conter quantas instruções ESQL forem necessárias para desempenhar sua função.
Alternativamente, em vez de fornecer um corpo ESQL para a rotina, você pode especificar uma cláusula LANGUAGE que não seja ESQL. Você pode, então, utilizar a cláusula EXTERNAL NAME para fornecer uma referência ao corpo real da rotina, onde quer que esteja localizada externamente, para o intermediário. Para obter mais informações sobre como usar a cláusula EXTERNAL NAME, consulte Chamando Procedimentos Armazenados e Chamando uma Rotina Java.
As rotinas de qualquer tipo de LANGUAGE pode ter parâmetros IN, OUT e INOUT. O responsável pela chamada pode transmitir vários valores para a rotina e receber vários valores atualizados de volta. Esses parâmetros retornados são adicionais a qualquer cláusula RETURNS que você tenha definido para a rotina. A cláusula RETURNS define o valor que a rotina retorna para o responsável pela chamada.
Rotinas que são implementadas em diferentes linguagens possuem suas próprias restrições nas quais os tipos de dados podem ser transmitidos ou retornados; estas restrições estão documentadas posteriormente nesta seção. O tipo de dados do valor retornado deve corresponder ao tipo de dados do valor definido para ser retornado da rotina. Além disso, se uma rotina for definida para ter um valor de retorno, o responsável pela chamada da rotina não poderá ignorá-lo. Para obter mais informações, consulte Instrução CALL.
Para qualquer tipo de linguagem ou rotina, o método de chamada da rotina deve corresponder ao modo de declaração da rotina. Se a rotina tiver uma cláusula RETURNS, utilize a sintaxe de chamada FUNCTION ou uma instrução CALL com uma cláusula INTO. Por outro lado, se uma rotina não tiver uma cláusula RETURNS, você deverá utilizar uma instrução CALL sem uma cláusula INTO.
Se o tipo de rotina for FUNCTION, o indicador de direção (IN, OUT, INOUT) será opcional para cada parâmetro. No entanto, é uma boa prática de programação especificar um indicador de direção para todas as novas rotinas de qualquer tipo para finalidades de documentação.
As variáveis ESQL que são declaradas como CONSTANT (ou referências a variáveis declaradas como CONSTANT) não têm permissão para ter a direção OUT ou INOUT.
As rotinas ESQL são escritas em ESQL e possuem uma cláusula LANGUAGE de ESQL. O corpo de uma rotina ESQL é geralmente uma instrução composta da forma BEGIN … END, que contém várias instruções para processar os parâmetros que são transmitidos para a rotina.
CREATE PROCEDURE swapParms (
IN parm1 CHARACTER,
OUT parm2 CHARACTER,
INOUT parm3 CHARACTER )
BEGIN
SET parm2 = parm3;
SET parm3 = parm1;
END;
Este procedimento de exemplo mostra o uso recursivo de uma rotina ESQL. Ele analisa uma árvore, visitando todos os locais no ponto inicial especificado, e abaixo dele, e relata o que foi localizado:
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;
Ao receber a seguinte mensagem de entrada:
<Person>
<Nome>John Smith</Nome>
<Salary period='monthly' taxable='yes'>-1200</Salary>
</Person>
o procedimento produz a seguinte saída, que foi formatada manualmente:
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
Uma rotina .NET é implementada como um método .NET e possui uma cláusula LANGUAGE de .NET ou CLR. Para rotinas .NET, o ExternalRoutineName deve conter o nome da classe e o nome do método .NET a ser chamado. Especifique o ExternalRoutineName como neste exemplo:
>>--"-- className---.---methodName--"--------------><
Em que className identifica
a classe que contém o método e methodName identifica o método a ser chamado. Se a classe fizer parte de um Namespace ou for uma classe aninhada, a parte do identificador de classes deverá incluir todos os nomes de Namespace e de classes aninhadas; por exemplo, "IBM.Broker.test.MyOuterClass.MyNestedClass.MyMethod"Para localizar a classe .NET, o broker procura o GAC e o local de base AppDomain do conjunto especificado.
Qualquer método .NET que você queira chamar deverá ter um método estático público. Além disso, todos os parâmetros devem estar listados nas Tabelas de Mapeamento de Tipos de Dados ESQL a .NET. Além disso, se o método tiver um tipo de retorno, o tipo de retorno deverá estar listado na tabela de mapeamento do tipo de dados IN.
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;
-- or
SET ReturnVar = Swap ( intVar1, intVar2, intVar3);
Define um procedimento que representa um Método .NET que não tem valor de retorno com três parâmetros Nullable de direções variadas.
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;
}
}
>>--"-- className---.---methodName--"--------------><
em
que className identifica a classe que contém o método e
methodName identifica o método a ser chamado. Se a classe fizer parte de um pacote, o identifador de classe
deverá incluir o prefixo completo do pacote; por exemplo, "com.ibm.broker.test.MyClass.myMethod" Para localizar a classe Java, o intermediário utiliza o método de procura descrito em Implementando Classes Java.
public static <return-type> <method-name> (< 0 - N parameters>)
Em que <return-type> deve estar na lista de tipos de dados IN Java na tabela em Mapeamento de Tipo de Dados ESQL para Java (excluindo o tipo REFERENCE, que não é permitido como um valor de retorno) ou o tipo de dados void Java. Os tipos de dados do parâmetro também devem estar na tabela Mapeamento de Tipo de Dados ESQL para Java. Além disso, o método Java não pode ter a cláusula exception throws em sua assinatura.
A cláusula na seção JavaClassLoader aplica-se somente a rotinas de LANGUAGE JAVA. A cláusula CLASSLOADER é opcional; se você não especificar essa cláusula, a classe Java será carregada pelo carregador de classe EGShared. Para obter informações adicionais, consulte o Carregamento de Classe do Nó JavaCompute e o Serviço Configurável JavaClassLoader.
É possível usar a API do nó definido pelo usuário Java em seu método Java, se você observar as restrições documentadas em Restrições com Rotinas Java. Para obter informações adicionais sobre como utilizar a API Java, consulte Compilando um Nó Java Definido pelo Usuário.
Esta rotina contém três parâmetros de diversas direções e retorna um inteiro, que é mapeado para um tipo de retorno Java de java.lang.Long.
CREATE FUNCTION myProc1( IN P1 INTEGER, OUT P2 INTEGER, INOUT P3 INTEGER )
RETURNS INTEGER
LANGUAGE JAVA
EXTERNAL NAME "com.ibm.broker.test.MyClass.myMethod1";
É possível utilizar o seguinte ESQL para chamar myProc1:
CALL myProc1( intVar1, intVar2, intVar3) INTO intReturnVar3;
-- or
SET intReturnVar3 = myProc1( intVar1, intVar2, intVar3);
Esta rotina contém três parâmetros de diversas direções e possui um tipo de retorno Java de void.
CREATE PROCEDURE myProc2( IN P1 INTEGER, OUT P2 INTEGER, INOUT P3 INTEGER )
LANGUAGE JAVA
EXTERNAL NAME "com.ibm.broker.test.MyClass.myMethod2";
Você deve utilizar o seguinte ESQL para chamar myProc2:
CALL myProc2(intVar1, intVar2, intVar3);
A classe Java a seguir fornece um método para cada um dos exemplos Java precedentes:
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) { ... }
/* Quando qualquer um desses métodos é chamado:
P1 pode ou não ser NULL (dependendo do valor de intVar1).
P2[0] é sempre NULL (qualquer que seja o valor de intVar2).
P3[0] pode ou não ser NULL (dependendo do valor de intVar3).
Isso é igual às rotinas ESQL LANGUAGE.
Quando esses métodos retornam:
intVar1 é inalterado
intVar2 pode ainda ser NULL ou talvez tenha sido alterado
intVar3 talvez contenha o mesmo valor ou talvez tenha sido alterado.
Isso é igual às rotinas ESQL LANGUAGE.
Quando myMethod1 retorna: intReturnVar3 é NULL (se o
método retornar NULL) ou contém o valor retornado pelo
método.
*/
}
CREATE FUNCTION myMethod1 ( IN P1 INTEGER, IN P2 INTEGER )
RETURNS INTEGER
LANGUAGE JAVA
EXTERNAL NAME "com.ibm.broker.test.MyClass.myMethod1"
CLASSLOADER "myClassLoader";
Tipos de Dados ESQL1 | Tipos de Dados IN Java | Tipos de Dados INOUT e OUT Java |
---|---|---|
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 | Não Suportado | Não Suportado |
BOOLEAN | java.lang.Boolean | java.lang.Boolean[] |
REFERENCE (para uma árvore de mensagens) 3 4 5 6 | com.ibm.broker.plugin.MbElement | com.ibm.broker.plugin.MbElement[] (Suportado para INOUT. Não suportado para OUT) |
ROW | Não Suportado | Não Suportado |
LIST | Não Suportado | Não Suportado |
Por exemplo, se uma referência ESQL a OutputRoot.XML.Test for transmitida para um método Java como um MbElement INOUT, mas um MbElement diferente for retornado a ESQL quando a chamada for retornada, o elemento diferente também deverá apontar para algum lugar na árvore OutputRoot.
Uma REFERÊNCIA a uma variável escalar pode ser utilizada na CHAMADA de um método Java, desde que o tipo de dados da variável ao qual a referência se refere corresponda ao tipo de dados correspondente na assinatura de programa Java.
É possível criar encadeamentos em seu método. No entanto, os encadeamentos criados não devem utilizar APIs Java e é necessário retornar o controle ao intermediário.
Todas as restrições que se aplicam ao uso da API Java também se aplicam a métodos Java chamados a partir de ESQL.
O método mais eficiente e flexível de implementação no intermediário é incluir seu arquivo JAR no arquivo BAR. Isso pode ser feito manualmente ou automaticamente utilizando o WebSphere Message Broker Toolkit.
Se a classe WebSphere Message Broker Toolkit finds the correct Java dentro de um projeto Java de referência for aberto no espaço de trabalho, ele compilará automaticamente a classeJava em um arquivo JAR e o incluirá ao arquivo BAR. Este procedimento é o mesmo procedimento seguido para implementar um nó JavaCompute em um JAR, conforme descrito em Carregamento de Classe de Nó Definido pelo Usuário.
Ao implementar um arquivo JAR do WebSphere Message Broker Toolkit, o fluxo que foi reimplementado recarregará o arquivo JAR contido no arquivo BAR.
Os arquivos também serão recarregados se o fluxo de mensagens que se refere a uma classe Java for parado e reiniciado. Certifique-se de parar e reiniciar (ou reimplementar) todos os fluxos que se referem ao arquivo JAR que você deseja atualizar. Essa ação evita o problema de alguns fluxos serem executados com a versão antiga do arquivo JAR e outros fluxos executados com a nova versão.
O WebSphere Message Broker Toolkit implementa apenas arquivos JAR; ele não implementa arquivos de classe Java independentes.
Você deve concluir esta ação manualmente; não pode utilizar o WebSphere Message Broker Toolkit.
Neste método, a reimplementação do fluxo de mensagens não recarrega as classes Java referidas; nem pára e reinicia o fluxo de mensagens. A única maneira de recarregar as classes neste caso é parar e reiniciar o próprio intermediário.
Para ativar o intermediário para localizar uma classe Java, assegure que ele esteja em um dos locais precedentes. Se o intermediário não puder localizar a classe especificada, ele gerará uma exceção.
Embora você tenha as opções mostradas anteriormente ao implementar o arquivo JAR, usar o WebSphere Message Broker Toolkit para implementar o arquivo BAR fornece maior flexibilidade ao reimplementar o arquivo JAR.
CREATE FUNCTION não suporta rotinas de banco de dados. Utilize CREATE PROCEDURE para definir uma rotina de banco de dados.