Sentencia CREATE FUNCTION

Las sentencias CREATE FUNCTION y CREATE PROCEDURE definen una función o procedimiento que se pueden llamar, normalmente denominadas rutinas.

SINTAXIS

Notas:
  1. Si el tipo de rutina es FUNCTION, el indicador de dirección (IN, OUT, INOUT) es opcional para cada parámetro. Sin embargo, en programación se recomienda especificar un indicador de dirección para todas las nuevas rutinas de cualquier tipo.
  2. Cuando se utiliza la cláusula NAMESPACE o NAME, su valor es implícitamente constante y de tipo CHARACTER. Para obtener información acerca de cómo utilizar las variables CONSTANT, consulte Sentencia DECLARE.
  3. Si el tipo de rutina es FUNCTION, no se puede especificar el lenguaje (LANGUAGE) DATABASE.

Visión general

Las sentencias CREATE FUNCTION y CREATE PROCEDURE definen una función o procedimiento que se pueden llamar, normalmente denominadas rutinas.

Nota: En versiones anteriores del producto, CREATE FUNCTION y CREATE PROCEDURE tenían distintas usos y posibilidades. Sin embargo, posteriormente se han ampliado hasta el punto de que sólo quedan unas pocas diferencias. Los únicos elementos en los que difieren las funciones de los procedimientos se listan en las notas 1 y 3 debajo del diagrama de sintaxis.

Las rutinas son útiles para crear bloques de código reutilizables que se pueden ejecutar independientemente muchas veces. Pueden implementarse como una serie de sentencias ESQL, un método Java o un procedimiento almacenado en una base de datos. Esta flexibilidad significa que algunas de las cláusulas en el diagrama de sintaxis de no son aplicables (o permitidas) a todos los tipos de rutina.

Cada rutina tiene un nombre, que debe ser exclusivo dentro del esquema al que pertenece. Esto significa que no se pueden sobrecargar los nombre de las rutinas; si el intermediario detecta que se ha sobrecargado una rutina, genera una excepción.

La cláusula LANGUAGE especifica el lenguaje en que se escribe el cuerpo de la rutina. Las opciones son:
DATABASE
Se llama al procedimiento como un procedimiento almacenado en la base de datos.
ESQL
Se llama al procedimiento como una rutina ESQL.
JAVA
Se llama al procedimiento como un método estático en una clase Java.
No especificado
Si no especifica la cláusula LANGUAGE, el lenguaje por omisión es ESQL, a menos que especifique la cláusula EXTERNAL NAME, en cuyo caso el lenguaje por omisión es DATABASE.
El uso de la cláusula LANGUAGE tiene algunas limitaciones. No utilice:
  • La opción ESQL con una cláusula EXTERNAL NAME
  • Las opciones DATABASE o JAVA sin una cláusula EXTERNAL NAME
  • La opción DATABASE con el tipo de rutina FUNCTION

Especifique el nombre de la rutina utilizando la cláusula NombreRutina y los parámetros de la rutina utilizando la cláusula ListaParámetros. Si la cláusula LANGUAGE especifica ESQL, la rutina debe implementarse utilizando una sola sentencia ESQL. Esta sentencia es muy útil si es una sentencia compuesta (BEGIN ... END) ya que entonces puede contener tantas sentencias ESQL como sea necesario para cumplir su función.

De forma alternativa, en lugar de proporcionar un cuerpo ESQL para la rutina, puede especificar una cláusula LANGUAGE distinta de ESQL. Esto le permite utilizar la cláusula EXTERNAL NAME para proporcionar una referencia al cuerpo real de la rutina, dondequiera que se ubique fuera del intermediario. Para obtener más información sobre la utilización de la cláusula EXTERNAL NAME, consulte Invocar procedimientos almacenados y Llamada a una rutina Java.

Las rutinas con LANGUAGE de cualquier tipo pueden tener parámetros IN, OUT e INOUT. Esto permite al canal de llamada pasar varios valores a la rutina y recibir de vuelta varios valores actualizados. Esto es además de cualquier cláusula RETURNS que pueda tener la rutina. La cláusula RETURNS permite a la rutina devolver un valor al canal de llamada.

Las rutinas implementadas en distintos lenguajes tienen sus propias restricciones sobre qué tipos de datos pueden pasarse o devolverse; estos tipos de datos se indican más abajo. El tipo de datos del valor devuelto debe coincidir con el tipo de datos del valor definido para retorno desde la rutina. Además, si una rutina está definida para que tenga un valor de retorno, el canal de llamada de la rutina no puede ignorarlo. Para obtener más detalles, consulte Sentencia CALL.

Las rutinas pueden definirse tanto en un módulo como en un esquema. Las rutinas definidas en un módulo son locales en el ámbito del nodo actual, lo cual significa que sólo puede llamarlas el código que pertenece al mismo módulo (o nodo). Sin embargo, a las rutinas definidas en el ámbito de esquema puede llamarlas:
  • Código en el mismo esquema.
  • Código en cualquier otro esquema, si se satisface alguna de estas condiciones:
    1. La cláusula PATH del otro esquema contiene la vía de acceso a la rutina llamada, o
    2. Se llama a la rutina utilizando su nombre totalmente calificado (que consta de su nombre y el prefijo con el nombre del esquema, separados por un punto).
Por tanto, si tiene que invocar la misma rutina en más de un nodo, defínala en un esquema.

Para cualquier lenguaje o tipo de rutina, el método de invocación de la rutina debe coincidir con la forma de declaración de la rutina. Si la rutina tiene una cláusula RETURNS, utilice la sintaxis de invocación FUNCTION o una sentencia CALL con una cláusula INTO. Y a la inversa, si una rutina no tiene ninguna cláusula RETURNS, debe utilizar una sentencia CALL sin una cláusula INTO.

Direcciones de parámetros

Los parámetros que se pasan a las rutinas siempre tienen una dirección asociada a ellos. Puede ser uno de los valores siguientes:
IN
La rutina no puede cambiar el valor del parámetro. Se permite el valor NULL para el parámetro y puede pasarse a la rutina.
OUT
Cuando la rutina llamada lo recibe, el parámetro pasado a la rutina siempre tiene el valor NULL del tipo de datos correcto. Esto sucede independientemente del valor que tenía antes de llamar a la rutina. La rutina puede cambiar el valor del parámetro.
INOUT
INOUT es un parámetro IN y OUT a la vez. Pasa un valor a la rutina y ésta puede cambiar dicho valor. Se permite el valor NULL para el parámetro y puede pasarse a y desde la rutina.

Si el tipo de rutina es FUNCTION, el indicador de dirección (IN, OUT, INOUT) es opcional para cada parámetro. Sin embargo, en programación se recomienda especificar un indicador de dirección para todas las nuevas rutinas de cualquier tipo.

Las variables ESQL que se declaran como CONSTANT (o las referencias a las variables declaradas como CONSTANT) no pueden tener la dirección OUT o INOUT.

Rutinas ESQL

Las rutinas ESQL están escritas en ESQL y tienen una cláusula LANGUAGE de ESQL. El cuerpo de una rutina ESQL normalmente es una sentencia compuesta de la forma BEGIN … END, con varias sentencias para procesar los parámetros pasados a la rutina.

Ejemplo 1 de ESQL

El ejemplo siguiente muestra el mismo procedimiento que en Ejemplo 1 de rutina de base de datos, pero implementado como una rutina ESQL en lugar de como un procedimiento almacenado. La sintaxis de CALL y el resultado de esta rutina son los mismos que en Restricciones en las rutinas Java.
CREATE PROCEDURE swapParms (
  IN parm1 CHARACTER,
  OUT parm2  CHARACTER,
  INOUT parm3 CHARACTER )
BEGIN
   SET parm2 = parm3;
   SET parm3 = parm1;
 END; 

Ejemplo 2 de ESQL

Este procedimiento de ejemplo muestra el uso repetitivo de una rutina ESQL. Analiza un árbol, visitando todos los lugares a partir de un punto inicial concreto, y genera informes sobre lo que ha encontrado:

SET OutputRoot.MQMD = InputRoot.MQMD;

  DECLARE answer CHARACTER;
  SET answer = '';

  CALL navigate(InputRoot.XML, answer);
  SET OutputRoot.XML.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;

Cuando se proporciona el siguiente mensaje de entrada:

<Person>
  <Name>John Smith</Name>
  <Salary period='monthly' taxable='yes'>-1200</Salary>
</Person>

el procedimiento genera la salida siguiente que se ha formateado 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

Rutinas Java

Una rutina Java se implementa como un método Java y tiene una cláusula LANGUAGE de JAVA. Para rutinas Java, NombreRutinaExterna debe contener el nombre de clase y el nombre de método del método Java a llamar. Especifique el NombreRutinaExterna de la siguiente manera:
 >>--"-- nombreClase---.---nombreMétodo--"--------------><
donde nombreClase identifica la clase que contiene el método y nombreMétodo identifica el método a invocar. Si la clase forma parte de un paquete, la parte correspondiente al identificador de clase debe incluir el prefijo del paquete completo; por ejemplo, "com.ibm.broker.test.MyClass.myMethod".

Para encontrar la clase Java, el intermediario busca tal como se describe en Despliegue de clases Java.

Cualquier método Java que desee invocar debe tener la siguiente signatura básica:
public static <return-type> <method-name> (<parámetros 0 - N>)

donde <return-type> debe estar en la lista de tipos de datos IN de Java en la tabla en Correlación de tipos de datos ESQL con Java (excluido el tipo REFERENCE, que no se permite como valor de retorno), o el tipo de datos vacío de Java. Los tipos de datos de parámetros también deben estar en la tabla Correlación de tipos de datos ESQL con Java. Además, no se permite que el método Java tenga una cláusula exception throws en su signatura.

La signatura del método Java debe coincidir con la declaración del método, de la rutina ESQL. Además, debe observar las normas siguientes:
  • Asegúrese de que el nombre del método Java, incluido el nombre de clase y cualquier calificador de paquete, coincida con el EXTERNAL NAME del procedimiento.
  • Si el tipo de retorno Java es void, no ponga una cláusula RETURNS en la definición de la rutina ESQL. A la inversa, si el tipo de retorno Java es not void, debe poner una cláusula RETURNS en la definición de la rutina ESQL.
  • Asegúrese de que cada dirección y tipo del parámetro coincida con la declaración ESQL, según las normas listadas en la tabla de Correlación de tipos de datos ESQL con Java.
  • Asegúrese de que los tipos de retorno de los métodos coincidan con el tipo de datos de la cláusula RETURNS.
  • Encierre EXTERNAL NAME entre comillas porque debe contener, al menos, “class.method”.
  • Si desea invocar un método Java sobrecargado, debe crear una definición ESQL aparte para cada método sobrecargado y asignar a cada definición ESQL un nombre de rutina exclusivo.

Puede utilizar la API Nodo definido por el usuario (UDN) de Java en su método Java, siempre y cuando observe las restricciones que se indican en Restricciones en las rutinas Java. Para obtener más información sobre la utilización de la API UDN, consulte Compilación de un nodo Java definido por el usuario.

Ejemplo 1 de rutina Java

Esta rutina contiene tres parámetros de diversas direcciones, y devuelve un entero, que se correlaciona con el 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";

Puede utilizar el ESQL siguiente para invocar myProc1:

CALL myProc1( intVar1, intVar2, intVar3) INTO intReturnVar3;
-- o
SET intReturnVar3 = myProc1( intVar1, intVar2, intVar3);

Ejemplo 2 de rutina Java

Esta rutina contiene tres parámetros de diversas direcciones y tiene un 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";

Debe utilizar el ESQL siguiente para invocar myProc2:

CALL myProc2(intVar1, intVar2, intVar3);

La siguiente clase Java proporciona un método para cada uno de los ejemplos Java anteriores:

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) { ... }

 /*  Cuando se llama a cualquiera de estos métodos:
    P1 puede ser o no NULL (dependiendo del valor de intVar1).
    P2[0] siempre es NULL (sea cual sea el valor de intVar2).
    P3[0] puede ser o no NULL (dependiendo del valor de intVar3).  
    Es lo mismo que con las rutinas LANGUAGE ESQL. 
    Estos métodos pueden devolver:
         intVar1 sin modificar
         intVar2 modificado o todavía con el valor NULL
         intVar3 modificado o todavía con el mismo valor
     Es lo mismo que con las rutinas LANGUAGE ESQL.
     
    Cuando myMethod1 devuelve: intReturnVar3 puede ser NULL (si el
    método devuelve NULL) o contiene el valor devuelto por el método.
 */
}

Correlación de tipos de datos ESQL con Java

La tabla siguiente resume las correlaciones de ESQL a Java.
Notas:
  • Sólo se pasan a Java los reiniciadores escalares Java.
  • Los tipos escalares ESQL se correlacionan con los tipos de datos Java como reiniciadores de objetos o como matrices de reiniciadores de objetos, dependiendo de la dirección del parámetro de procedimiento. Cada matriz de reiniciadores contiene exactamente un elemento.
  • Los reiniciadores de objetos escalares se utilizan para que puedan pasarse valores NULL a y desde los métodos Java.
Tipos de datos ESQL 1 Tipos de datos IN de Java Tipos de datos INOUT y OUT de 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 No soportado No soportado
BOOLEAN java.lang.Boolean java.lang.Boolean[]
REFERENCE (a un árbol de mensaje) 3 4 5 6 com.ibm.broker.plugin.MbElement com.ibm.broker.plugin.MbElement[] (Soportado para INOUT. No soportado para OUT)
ROW No soportado No soportado
LIST No soportado No soportado
  1. Las variables que se declaran como CONSTANT (o las referencias a las variables declaradas como CONSTANT) no pueden tener la dirección INOUT u OUT.
  2. El huso horario establecido en la variable Java no es importante, el huso horario necesario se obtiene en el ESQL de salida.
  3. El parámetro de referencia no puede ser NULL cuando se pasa a un método Java.
  4. La referencia no puede tener la dirección OUT cuando se pasa a un método Java.
  5. Si se vuelve a pasar un MbElement de Java a ESQL como un parámetro INOUT, debe apuntar a una ubicación en el mismo árbol de mensaje al que apuntaba el MbElement que se ha pasado en el método Java que se ha llamado.

    Por ejemplo, si se pasa una referencia ESQL a OutputRoot.XML.Test a un método Java como un MbElement INOUT, pero se vuelve a pasar un MbElement diferente a ESQL cuando se devuelve la llamada, el elemento diferente también debe apuntar a algún lugar del árbol OutputRoot.

  6. Un MbElement no se puede devolver desde un método Java con la cláusula RETURNS, ya que ninguna rutina ESQL puede devolver una referencia. No obstante, un elemento MbElement se puede devolver como un parámetro de dirección INOUT, dependiendo de las condiciones descritas en el punto 5 anterior.

Puede utilizarse una referencia (REFERENCE) a una variable escalar en la llamada (CALL) de un método Java, siempre que el tipo de datos de la variable a la que REFERENCE hace referencia coincida con el tipo de datos correspondiente en la signatura del programa Java.

Restricciones en las rutinas Java

Las siguientes restricciones se aplican a las rutinas Java invocadas desde ESQL:
  • Debe asegurarse de que el método Java sea seguro en ejecución multihebra (reentrante).
  • Las únicas conexiones de base de datos permitidas son las conexiones JDBC de tipo 4. Además, las operaciones de base de datos no forman parte de una transacción de intermediario; esto significa que no pueden ser controladas por un coordinador de recursos externo (tal como sería el caso en un entorno XA).
  • La API Nodo definido por el usuario (UDN) de Java sólo debería utilizarla la misma hebra que ha invocado el método Java.

    Está permitido generar hebras dentro de un método propio. No obstante, las hebras generadas no deben utilizar las API de plug-in de Java y se debe devolver el control al intermediario.

    Tenga en cuenta que todas las restricciones que se aplican al uso de la API UDN también se aplican a los métodos Java invocados desde ESQL.

  • Los métodos Java invocados desde ESQL no deben utilizar la clase MbNode. Esto significa que no pueden crear objetos de tipo MbNode, ni llamar a ninguno de los métodos de un objeto MbNode existente.
  • Si desea realizar trabajo MQ o JMS dentro de un método Java invocado desde ESQL, debe seguir las directrices de Nodo definido por el usuario (UDN) para realizar trabajo MQ y JMS en un UDN.

Despliegue de clases Java

Puede desplegar las clases Java dentro de un archivo JAR (Java Archive). Hay dos maneras de desplegar un archivo JAR en el intermediario:
  1. Añadiéndolo al archivo BAR (archivador de intermediario)

    La adición del archivo JAR al archivo BAR es el método más eficaz y flexible de desplegar en el intermediario.

    Puede añadir un archivo JAR manualmente en el archivo BAR, a mano o de forma automática utilizando las herramientas. Las herramientas es la manera más sencilla de añadir un archivo JAR a un archivo BAR.

    Si las herramientas encuentran la clase Java correcta dentro de un proyecto Java al que se hace referencia, abierto en un espacio de trabajo, compila automáticamente la clase Java en un archivo JAR y lo añade al archivo BAR. Este es el mismo procedimiento que se sigue para desplegar un nodo Compute de Java dentro de un JAR, tal como se describe en Carga de clases de nodo definido por el usuario.

    Al desplegar un archivo JAR desde las herramientas, un nuevo despliegue del archivo BAR que contiene el archivo JAR hace que el flujo que se ha vuelto a desplegar vuelva a cargar las clases Java a las que se hace referencia; al igual que sucede cuando se detiene y reinicia un flujo de mensajes que hace referencia a una clase Java. Asegúrese de detener y reiniciar (o volver a desplegar) todos los flujos que hacen referencia al archivo JAR que desea actualizar. Esto evita el problema de algunos flujos ejecutándose con la versión antigua del archivo JAR y otros flujos ejecutándose con la versión nueva.

    Observe que las herramientas sólo desplegarán un archivo JAR; no desplegarán un archivo de clases Java autónomo.

  2. Colocándolo en una de estas ubicaciones:
    1. La carpeta <VíaAccesoTrabajo>/shared-classes/ de la máquina donde se ejecuta el intermediario
    2. La variable de entorno CLASSPATH de la máquina donde se ejecuta el intermediario

    Este procedimiento debe efectuarse manualmente; no se pueden utilizar las herramientas.

    En este método, desplegar de nuevo el flujo de mensajes no hace que se vuelvan a cargar las clases Java a las que se hace referencia; ni tampoco si se detiene y reinicia el flujo de mensajes. En este caso, la única manera de volver a cargar las clases es detener y reiniciar el intermediario mismo.

Para que el intermediario pueda encontrar una clase Java, asegúrese de que esté en una de las ubicaciones anteriores. Si el intermediario no puede encontrar la clase especificada, genera una excepción.

Aunque tiene las opciones que se muestran más arriba al desplegar el archivo JAR, al permitir que las herramientas desplieguen el archivo BAR se ofrecerá mayor flexibilidad al volver a desplegar el archivo JAR.

Rutinas de base de datos

CREATE FUNCTION no da soporte a las rutinas de base de datos. Utilice CREATE PROCEDURE para definir una rutina de base de datos.

Conceptos relacionados
Visión general de ESQL
Tareas relacionadas
Desarrollo de ESQL
Invocar procedimientos almacenados
Compilación de un nodo Java definido por el usuario
Referencia relacionada
Diagramas de sintaxis: tipos disponibles
Sentencias ESQL
Sentencia CALL
Tabla de correlación de tipos de datos ESQL a Java
Información relacionada
../com.ibm.etools.mft.javanodeAPI.doc/com/ibm/broker/plugin/package-overview.html
Avisos | Marcas registradas | Descargas | Biblioteca | Soporte | Su opinión
Copyright IBM Corporation 1999, 2006 Última actualización: 22/08/2006
ak04960_