Instrução CREATE FUNCTION

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.

SINTAXE

Notas:
  1. Se o tipo de rotina for FUNCTION, o indicador de direção (IN, OUT ou INOUT) será opcional para cada parâmetro. Entretanto, para fins de documentação, é uma boa prática de programação especificar um indicador de direção para todas as novas rotinas; se você não especificar a direção, um valor padrão igual a IN será utilizado.
  2. Quando a cláusula NAMESPACE ou NAME é utilizada, seu valor é implicitamente CONSTANT e do tipo CHARACTER. Para obter informações sobre a utilização de variáveis CONSTANT, consulte Instrução DECLARE.
  3. Se o tipo de rotina for FUNCTION, não é possível especificar um LANGUAGE de DATABASE.

Visão Geral

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. Você pode implementá-las como uma série de instruções ESQL, um método Java 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 detetar que um nome de rotina foi sobrecarregado, ele exibirá uma exceção.

A cláusula LANGUAGE especifica a linguagem em que o corpo da rotina é escrito. As opções são:
DATABASE
O procedimento é chamado como um procedimento armazenado do banco de dados.
ESQL
O procedimento é chamado como uma rotina ESQL.
JAVA
O procedimento é chamado de método estático em uma classe Java.
Não Especificado
Se você não especificar a cláusula LANGUAGE, a linguagem padrão será ESQL, a menos que você especifique a cláusula EXTERNAL NAME (nesse caso, a linguagem padrão é DATABASE).
Existem restrições na utilização da cláusula LANGUAGE. Você não pode utilizar:
  • A opção ESQL com uma cláusula EXTERNAL NAME
  • As opções DATABASE ou JAVA sem uma cláusula EXTERNAL NAME
  • A opção DATABASE com um tipo de rotina de FUNCTION

Especifique o nome da rotina utilizando a cláusula RoutineName e os parâmetros da rotina utilizando a cláusula ParameterList. Se a cláusula LANGUAGE especificar ESQL, implemente a rotina utilizando 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 informações adicionais sobre como utilizar 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.

As rotinas podem ser definidas em um módulo ou esquema. As rotinas definidas em um módulo são locais em escopo para o nó atual, o que significa que apenas o código pertencente a esse mesmo módulo (ou nó) pode chamá-las. Rotinas que são definidas em um esquema, entretanto, podem ser chamadas utilizando uma das seguintes opções:
  • Código no mesmo esquema
  • Código em qualquer outro esquema, se uma das seguintes condições for aplicável:
    • A cláusula PATH do outro esquema contém o caminho para a rotina chamada
    • A rotina chamada é chamada utilizando seu nome completo (que é seu nome, prefixado por seu nome do esquema, separado por um ponto)
Portanto, se você precisar chamar a mesma rotina em mais de um nó, defina-a em um esquema.

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.

Direções de Parâmetros

Os parâmetros que são transmitidos para rotinas sempre possuem uma direção associada a eles, que é um dos seguintes tipos:
IN
O valor do parâmetro não pode ser alterado pela rotina. Um valor NULL para o parâmetro é permitido e pode ser transmitido para a rotina.
OUT
Quando ele é recebido pela rotina chamada, o parâmetro que é transmitido para a rotina sempre possui um valor NULL do tipo de dados correto. Esse valor é configurado independentemente de seu valor antes da chamada da rotina. A rotina tem permissão para alterar o valor do parâmetro.
INOUT
INOUT é um parâmetro IN e OUT. Ele transmite um valor para a rotina e o valor que é transmitido pode ser alterado pela rotina. É permitido um valor NULL para o parâmetro e ele pode ser transmitido para e a partir da rotina.

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.

Rotinas ESQL

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.

Exemplo 1 de ESQL

O exemplo a seguir mostra o mesmo procedimento que no Exemplo 1 de Rotina de Banco de Dados, mas ele é implementado como uma rotina ESQL e não como um procedimento armazenado. A sintaxe e os resultados de CALL desta rotina são iguais àqueles no Restrições em Rotinas Java.
CREATE PROCEDURE swapParms (
    IN parm1 CHARACTER,
    OUT parm2  CHARACTER,
    INOUT parm3 CHARACTER )
  BEGIN
      SET parm2 = parm3;
      SET parm3 = parm1;
       END;

Exemplo 2 de ESQL

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

Rotinas Java

Uma rotina Java é implementada como um método Java e possui uma cláusula LANGUAGE de JAVA. Para rotinas Java, ExternalRoutineName deve conter o nome da classe e o nome do método do método Java a ser chamado. Especifique o ExternalRoutineName como este:
>>--"-- 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, a parte do identificador de classe deve 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.

Qualquer método Java que você deseja chamar deve ter a seguinte assinatura básica:
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 uma cláusula exception throws em sua assinatura.

A assinatura do método Java deve corresponder à declaração da rotina ESQL do método. Você também deve observar as seguintes regras:
  • Certifique-se de que o nome do método Java, incluindo o nome da classe e os qualificadores do pacote, corresponda ao EXTERNAL NAME do procedimento.
  • Se o tipo de retorno Java for void, não coloque uma cláusula RETURNS na definição da rotina ESQL. De forma oposta, se o tipo de retorno Java não for void, você deverá colocar uma cláusula RETURNS na definição de rotina ESQL.
  • Assegure-se de que o tipo e a direção de cada parâmetro corresponda à declaração ESQL, de acordo com as regras listadas na tabela em Mapeamento de Tipo de Dados ESQL para Java.
  • Assegure-se de que o tipo de retorno do método corresponda ao tipo de dados da cláusula RETURNS.
  • Coloque EXTERNAL NAME entre aspas porque ele deve conter pelo menos "class.method".
  • Se desejar chamar um método Java sobrecarregado, será necessário criar uma definição ESQL separada para cada método sobrecarregado e fornecer a cada definição ESQL um nome de rotina exclusivo.

Você pode utilizar a API do nó definido pelo usuário Java em seu método Java, desde que observe as restrições documentadas em Restrições em Rotinas Java. Para obter informações adicionais sobre como utilizar a API Java, consulte Compilando um Nó Java Definido pelo Usuário.

Exemplo de Rotina Java 1

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);

Exemplo de Rotina Java 2

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 pode ter sido alterado
         intVar3 pode conter o mesmo valor ou pode ter 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.
 */
}

Mapeamento de Tipo de Dados ESQL para Java

A tabela a seguir resume os mapeamentos de ESQL para Java.
Notas:
  • Apenas os wrappers escalares Java são transmitidos para Java.
  • Os tipos escalares ESQL são mapeados para tipos de dados Java como wrappers de objeto, ou matrizes de wrappers de objeto, dependendo da direção do parâmetro de procedimento. Cada matriz de wrapper contém exatamente um elemento.
  • Os wrappers de objeto escalares são utilizados para permitir que valores NULL sejam transmitidos para e a partir de métodos Java.
Tipos de Dados ESQL 1 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
  1. As variáveis que são declaradas como CONSTANT (ou referências a variáveis que são declaradas CONSTANT) não têm permissão para terem a direção INOUT ou OUT.
  2. O fuso horário configurado na variável Java não é importante; você obtém o fuso horário necessário na ESQL de saída.
  3. O parâmetro de referência não pode ser NULL quando transmitido para um método Java.
  4. A referência não pode ter a direção OUT quando transmitida para um método Java.
  5. Se um MbElement for retornado de Java para ESQL como um parâmetro INOUT, ele deverá apontar para um local na mesma árvore de mensagens apontada pelo MbElement que foi transmitido para o método Java chamado.

    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.

  6. Um MbElement não pode ser retornado de um método Java com a cláusula RETURNS, porque nenhuma rotina ESQL pode retornar uma referência. No entanto, um MbElement pode ser retornado como um parâmetro de direção INOUT sujeito às condições descritas no ponto 5.

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.

Restrições em Rotinas Java

As restrições a seguir se aplicam a rotinas Java chamadas a partir de ESQL:
  • O método Java deve ser thread-safe (reentrante).
  • As conexões com o banco de dados devem ser JDBC tipo 2 ou tipo 4. Além disso, as operações do banco de dados não fazem parte de uma transação do intermediário e, portanto, não podem ser controladas por um coordenador de recursos externo (como é o caso em um ambiente XA).
  • A API do nó definido pelo usuário Java deve ser utilizada apenas pelo mesmo encadeamento que chamou o método 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.

  • Os métodos Java chamados a partir de ESQL não devem utilizar a classe MbNode. Portanto, eles não podem criar objetos do tipo MbNode ou chamar qualquer um dos métodos em um objeto MbNode existente.
  • O trabalho do WebSphere MQ ou do JMS feito dentro de um método Java que é chamado a partir de ESQL deve ser feito de acordo com as diretrizes para desempenhar o trabalho do WebSphere MQ e JMS em um nó definido pelo usuário. Início da mudançaConsulte Planejando Nós de Entrada Definidos pelo Usuário.Fim da mudança

Implementando Classes Java

Você pode implementar suas classes Java para um intermediário em um arquivo JAR (Java Archive) utilizando um dos dois métodos a seguir:
  1. Incluir o arquivo JAR no arquivo BAR (broker archive)

    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 ambiente de trabalho.

    Se a classe ambiente de trabalho 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 do Nó Definido pelo Usuário.

    Ao implementar um arquivo JAR do ambiente de trabalho, 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 ambiente de trabalho implementa apenas arquivos JAR; ele não implementa arquivos de classe Java independente.

  2. Armazenar o arquivo JAR em um dos seguintes locais:
    1. A pasta workpath/shared-classes/ na máquina que executa o intermediário
    2. A variável de ambiente CLASSPATH no computador que executa o intermediário

    Você deve concluir esta ação manualmente; não pode utilizar o ambiente de trabalho.

    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 quando implementou o arquivo JAR, utilizar o ambiente de trabalho para implementar o arquivo BAR fornece maior flexibilidade ao reimplementar o arquivo JAR.

Rotinas de Banco de Dados

CREATE FUNCTION não suporta rotinas de banco de dados. Utilize CREATE PROCEDURE para definir uma rotina de banco de dados.

Conceitos relacionados
Visão Geral do ESQL
Tarefas relacionadas
Desenvolvendo ESQL
Chamando Procedimentos Armazenados
Compilando um Nó Java Definido pelo Usuário
Incluindo Arquivos em um Broker Archive
Referências relacionadas
Diagramas de Sintaxe: Tipos Disponíveis
instruções ESQL
Instrução CALL
Instrução CREATE PROCEDURE
Tabela de Mapeamento de Tipo de Dados de ESQL para Java
Informações relacionadas
API de Extensões Definidas pelo Usuário Java
Avisos | Marcas Registradas | Downloads | Biblioteca | Suporte | Feedback

Copyright IBM Corporation 1999, 2009Copyright IBM Corporation 1999, 2009.
Última atualização : 2009-02-13 16:12:42

ak04960_