Crear el archivo C++ para el UDA
Para empezar, utilice cualquier editor de texto para crear el archivo C++. Su archivo C++ debe incluir el archivo de cabecera ' udxinc.h ', que contiene las declaraciones necesarias para los agregados definidos por el usuario y el procesamiento en las SPU.
#include "udxinc.h"
Además, asegúrese de que declara todos los archivos de cabecera de biblioteca C++ estándar que puede necesitar el agregado. Si la UDA requiere bibliotecas compartidas definidas por el usuario, asegúrese de que toma nota del nombre de las bibliotecas porque los necesitará cuando registre la UDA en la base de datos.
Las bibliotecas compartidas definidas por el usuario deben existir en la base de datos antes de que pueda registrar la UDA y especificar dichas bibliotecas como dependencias. Puede registrar la UDA sin especificar las dependencias de biblioteca y, después de añadir las bibliotecas, utilice el mandato ALTER AGGREGATE para actualizar la definición de UDA 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.
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"
using namespace nz::udx_ver2;Esta sección utiliza udx_ver2 como el espacio de nombres predeterminado para los ejemplos que aparecen a continuación. 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 la versión 1 y la versión 2. Puede continuar creando los UDA de UDX versión 1 y los UDA de la versión 2; ambas versiones operan en el release 6.0.x o sistemas posteriores. Sin embargo, los UDA de la versión 1 funcionan en la versión ' Netezza Performance Server ' ' 5.0.x y sistemas posteriores, por lo que podrían ser más portables para tus sistemas ' Netezza Performance Server.
#include "udxinc.h"
using namespace nz::udx_ver2;
class CPenMax: public nz::udx_ver2::Uda
{
public:
};class CPenMax : public nz::udx_ver2::Uda
{
public:
static nz::udx_ver2::Uda* instantiate(UdxInit *pInit)
virtual void initializeState();
virtual void accumulate();
virtual void merge();
virtual ReturnValue finalResult();
};
nz::udx_ver2::Uda* CPenMax::instantiate(UdxInit *pInit)
{
return new CPenMax(pInit);
}- 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 el acceso a la especificación de memoria, la configuración del registro y el entorno de UDX en el constructor (consulte Entorno de UDX). Crea un objeto de un tipo de clase derivada utilizando el nuevo operador y devolviéndolo (como tipo de clase base Uda) 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 ofrece un ejemplo:
class CPenMax : public nz::udx_ver2::Uda { public: CPenMax(UdxInit *pInit) : Uda(pInit) { } static nz::udx_ver2::Uda* instantiate(UdxInit *pInit); virtual void initializeState(); virtual void accumulate(); virtual void merge(); virtual ReturnValue finalResult(); }; nz::udx_ver2::Uda* CPenMax::instantiate(UdxInit *pInit) { return new CPenMax(pInit); } - El método initializeState() se llama para permitir al implementador inicializar el estado necesario que se utiliza en el UDA. El estado de un UDA es uno o más valores que deben ser tipos de datos válidos Netezza Performance Server. El estado lo conserva automáticamente el motor de tiempo de ejecución entre fragmentos de código, si es necesario. Para calcular el penúltimo máximo, la función debe seguir a los dos números más grandes en las variables de estado. El método initializeState() establece ambas variables en NULL. Los estados se declaran en el mandato CREATE AGGREGATE, que se describe más tarde. A continuación se ofrece un ejemplo:
void CPenMax::initializeState() { setStateNull(0, true); // set current max to null setStateNull(1, true); // set current penmax to null } - El método accumulate() se llama una vez por fila y añade la contribución de sus argumentos al estado del acumulador. Actualiza los estados para mantener los dos valores más altos en los estados correctos. Además de obtener los argumentos a través de
int curVal = int32Arg(0);, el método recupera las dos variables de estado utilizando las funciones int32State(int) y isStateNull(int). El método accumulate actualiza los estados según sea necesario.void CPenMax::accumulate() { int *pCurMax = int32State(0); bool curMaxNull = isStateNull(0); int *pCurPenMax = int32State(1); bool curPenMaxNull = isStateNull(1); int curVal = int32Arg(0); bool curValNull = isArgNull(0); if ( !curValNull ) { // do nothing if argument is null - can't //affect max or penmax if ( curMaxNull ) { // if current max is null, this arg //becomes current max setStateNull(0, false); // current max no longer null *pCurMax = curVal; } else { if ( curVal > *pCurMax ) { // if arg is new max setStateNull(1, false); // then prior current max // becomes current penmax *pCurPenMax = *pCurMax; *pCurMax = curVal; // and current max gets arg } else if ( curPenMaxNull || curVal > *pCurPenMax ){ // arg might be greater than current penmax setStateNull(1, false); // it is *pCurPenMax = curVal; } } } } - El método merge() se llama con argumentos de un segundo conjunto de variables de estado y fusiona este segundo estado en sus propias variables de estado. Este método es necesario porque el sistema Netezza Performance Server es una arquitectura de procesamiento en paralelo, y los estados agregados de todas las SPU se envían al host, donde se consolidan en un único estado de agregación fusionado. El método merge() fusiona dos estados, manejando todos los estados de valores null correctamente. Uno de los estados se pasa normalmente como en accumulate(). El segundo estado se pasa como argumentos, requiriendo el uso de funciones de recuperación de argumentos como int32Arg(int) y isArgNull(int) a recuperar. A continuación se ofrece un ejemplo:
void CPenMax::merge() { int *pCurMax = int32State(0); bool curMaxNull = isStateNull(0); int *pCurPenMax = int32State(1); bool curPenMaxNull = isStateNull(1); int nextMax = int32Arg(0); bool nextMaxNull = isArgNull(0); int nextPenMax = int32Arg(1); bool nextPenMaxNull = isArgNull(1); if ( !nextMaxNull ) { // if next max is null, then so is //next penmax and we do nothing if ( curMaxNull ) { setStateNull(0, false); // current max was null, // so save next max *pCurMax = nextMax; } else { if ( nextMax > *pCurMax ) { setStateNull(1, false); // next max is greater than current, so save next *pCurPenMax = *pCurMax; // and make current penmax prior current max *pCurMax = nextMax; } else if ( curPenMaxNull || nextMax > *pCurPenMax ) { // next max may be greater than current penmax setStateNull(1, false); // it is *pCurPenMax = nextMax; } } if ( !nextPenMaxNull ) { if ( isStateNull(1) ) { // can't rely on curPenMaxNull here, might have // change state var null flag above setStateNull(1, false); // first non-null penmax, // save it *pCurPenMax = nextPenMax; } else { if ( nextPenMax > *pCurPenMax ) { *pCurPenMax = nextPenMax; // next penmax greater than current, save it } } } } } - El método finalResult() devuelve el valor de agregación final del estado acumulado. Un ejemplo puede ser una implementación de UDA del promedio de agregación, donde el método finalResult() divide la suma por el recuento para dar una media. En este ejemplo, el método finalResult() recopila uno de los estados y lo devuelve utilizando la macro NZ_UDX_RETURN_INT32 de forma simular a evaluate() en el caso de UDF.
ReturnValue CPenMax::finalResult() { int curPenMax = int32Arg(1); bool curPenMaxNull = isArgNull(1); if ( curPenMaxNull ) NZ_UDX_RETURN_NULL(); setReturnNull(false); NZ_UDX_RETURN_INT32(curPenMax); }
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. El método ' finalResult() ' puede acceder a todas las llamadas de la API de ayuda de tipos de datos y acceder a una lista de argumentos de estado que se enumeran en argumentos de estado UDA.