Crear el archivo C++ para la UDF

Para empezar, utilice cualquier editor de texto para crear el archivo C++. El nombre de archivo debe tener una extensión .cpp. Es posible que desee crear un directorio como /home/nz/udx_files como área para los archivos de código de UDX.

Su archivo C++ debe incluir el archivo de cabecera ' udxinc.h ', que contiene las declaraciones necesarias para las funciones definidas por el usuario y el procesamiento en las SPUs.

#include "udxinc.h"
Además, asegúrese de que declara todos los archivos de cabecera de biblioteca C++ estándar que puede necesitar la función. Si la UDF requiere bibliotecas compartidas definidas por el usuario, asegúrese de que toma nota del nombre de las bibliotecas porque los necesitará cuando registre la UDF en la base de datos. Por ejemplo:
#include "udxinc.h"
#include <string.h>
Nota: Las bibliotecas compartidas definidas por el usuario deben existir en la base de datos antes de poder registrar la UDF y especificar dichas bibliotecas como dependencias. Puede registrar la UDF sin especificar las dependencias de biblioteca y, después de añadir las bibliotecas, utilice el mandato ALTER FUNCTION para actualizar la definición de UDF con las dependencias correctas. Para obtener más información sobre las bibliotecas compartidas definidas por el usuario, consulte ' Crear una biblioteca compartida definida por el usuario.
Las funciones y clases de UDX para la API versión 2 se definen en un espacio de nombres denominado nz::udx_ver2. (Los UDX de la API versión 1 utilizan el espacio de nombres nz::udx.) El programa C++ debe hacer referencia al espacio de nombres correcto. Por ejemplo:
#include "udxinc.h"
#include <string.h>
using namespace nz::udx_ver2;
Nota: Esta sección utiliza ' udx_ver2 como espacio de nombres por defecto para los ejemplos que siguen. Las secciones señalan las diferencias con la versión 1 de UDX, y la referencia de funciones y agregados definidos por el usuario de ejemplo contiene ejemplos de definiciones de las versiones 1 y 2. Puede continuar creando las funciones de UDX versión 1 y las nuevas funciones de la versión 2; ambas funciones se ejecutan en el release 6.0.x. Sin embargo, las funciones de la versión 1 funcionan en sistemas ' Netezza Performance Server ' release ' 5.0.x y posteriores, por lo que podrían ser más portables para sus sistemas ' Netezza Performance Server '.
Para implementar una UDF, cree un objeto de clase que se derive de la clase base Udf. Siguiendo con el ejemplo customername:
#include "udxinc.h"
#include <string.h>

using namespace nz::udx_ver2;
class CCustomerName: public nz::udx_ver2::Udf
{
public:
};

Cada UDF debe implementar los dos métodos siguientes:

  • El método instantiate() se llama a través del motor de tiempo de ejecución para crear el objeto dinámicamente. La implementación estática debe estar fuera de la definición de clase. En la versión 2 de UDX, el método instantiate toma un argumentoUdxInit *pInit), que permite acceder a la especificación de memoria, la configuración de registro y el entorno UDX (consulte Entorno UDX). El constructor también debe tomar un objeto UdxInit y pasarlo al constructor de clase base. El método instantiate crea un objeto de un tipo de clase derivada utilizando el nuevo operador y devolviéndolo (como tipo de clase base Udf) al motor de tiempo de ejecución. El motor de tiempo de ejecución suprime el objeto cuando ya no es necesario. A continuación, se muestra un ejemplo del método instantiate para la API versión 2:
       #include "udxinc.h"
    #include <string.h>
    
    using namespace nz::udx_ver2;
    
    class CCustomerName: public nz::udx_ver2::Udf
    {
    public:
        CCustomerName(UdxInit *pInit) : Udf(pInit)
    {
    }
        static nz::udx_ver2::Udf* instantiate(UdxInit *pInit);
    };
    nz::udx_ver2::Udf* CCustomerName::instantiate(UdxInit *pInit)
    {
            return new CCustomerName(pInit);
    }
  • Se llama al método evaluate() una vez para cada fila de datos durante la ejecución.
       #include "udxinc.h"
    #include <string.h>
    
    using namespace nz::udx_ver2;
    
    class CCustomerName: public nz::udx_ver2::Udf
    {
    public:
        CCustomerName(UdxInit *pInit) : Udf(pInit)
    {
    }
        static nz::udx_ver2::Udf* instantiate(UdxInit *pInit);
        virtual nz::udx_ver2::ReturnValue evaluate()
        {
            // Code to be inserted here
        }
    };
    
    nz::udx_ver2::Udf* CCustomerName::instantiate(UdxInit *pInit)
    {
        return new CCustomerName(pInit);
    }
    

Puede implementar constructores y destructores según sea necesario. En la API versión 1, los constructores son opcionales. En la API versión 2, los constructores son necesarios; debe especificar un constructor aunque sólo invoque al constructor de clase base, como en el ejemplo anterior. Algunas acciones comunes a incluir en los constructores son las rutinas de reserva de memoria (ya que new y delete son relativamente caras), y la configuración de cualquier estructura necesaria para el cálculo (por ejemplo, la configuración de una matriz para rutinas de cifrado).

Para el ejemplo ' customername ', el UDF toma una cadena y devuelve el entero 1 si la cadena empieza por "Cliente A", de lo contrario devuelve el entero 0. El código para el método evaluate es el siguiente:
virtual nz::udx_ver2::ReturnValue evaluate()
    {
        StringArg *str;
        str = stringArg(0);              // 4
        int lengths = str->length;                  // 5
        char *datas = str->data;                    // 6
        int32 retval = 0;
        if (lengths >= 10)
            if (memcmp("Customer A",datas,10) == 0)
                            retval = 1;
        NZ_UDX_RETURN_INT32(retval);                 // 11
    }

En el programa de ejemplo, la línea 4 declara y usa una estructura StringArg para pasar el argumento a la UDF. Los argumentos para las UDF se recuperan utilizando funciones como StringArg. Si esta UDF toma un segundo argumento de serie, StringArg(1) debe hacer referencia al segundo argumento. Para obtener una lista completa de los tipos de argumentos admitidos y sus funciones de ayuda asociadas, consulte Referencia de la API de ayuda de tipos de datos. Las líneas 5 y 6 extraen la longitud y el puntero del carácter (char*) de la estructura StringArg.

Nota: El programa de ejemplo utiliza ' memcmp (no ' strcmp) porque las estructuras StringArg no están terminadas en cero (\0) en funciones o agregados definidos por el usuario. Por lo tanto, strcmp, strcpy, strlen, atol y las demás funciones que dependen de la presencia de un terminador nulo no funcionan. Si necesita utilizar esas funciones, debe copiar la serie en un almacenamiento intermedio y añadir manualmente el terminador nulo.

La línea 11 utiliza una macro UDX para devolver el valor calculado al motor de Netezza Performance Server. La macro NZ_UDX_RETURN_INT32 le ayuda a confirmar que el valor de retorno es del tipo esperado. Para obtener una lista de las macros de retorno disponibles, consulte Macros de valor de retorno UDX.

Para utilizar la función, debe compilarla y registrarla como función disponible en el sistema Netezza Performance Server.