Criar o arquivo C++ para a UDF

Para começar, use qualquer editor de texto para criar seu arquivo C++. O nome do arquivo deve ter uma extensão .cpp. Você pode desejar criar um diretório como /home/nz/udx_files como sua área para arquivos de código UDX.

Seu arquivo C++ deve incluir o arquivo de cabeçalho ' udxinc.h, que contém as declarações necessárias para funções definidas pelo usuário e processamento nas SPUs.

#include "udxinc.h"
Além disso, certifique-se de que você declara qualquer um dos arquivos de cabeçalho da standard C++ library que a função pode requerer. Se a UDF requerer qualquer biblioteca compartilhada definida pelo usuário, certifique-se de que você observa o nome das bibliotecas, pois você precisará deles quando registrar a UDF no banco de dados. Por exemplo:
#include "udxinc.h"
#include <string.h>
Observação: as bibliotecas compartilhadas definidas pelo usuário devem existir no banco de dados para que você possa registrar o UDF e especificar essas bibliotecas como dependências. É possível registrar a UDF sem especificar quaisquer dependências de biblioteca, e após a inclusão das bibliotecas, use o comando ALTER FUNCTION para atualizar a definição do UDF com as dependências corretas. Para obter mais informações sobre bibliotecas compartilhadas definidas pelo usuário, consulte Criar uma biblioteca compartilhada definida pelo usuário.
As classes e funções UDX para a versão 2 da API são definidas em um namespace chamado nz::udx_ver2. (Os UDXs da versão 1 da API usam o espaço de nome ' nz::udx ) Seu programa C++ deve referenciar o namespace correto. Por exemplo:
#include "udxinc.h"
#include <string.h>
using namespace nz::udx_ver2;
Observação: Esta seção usa " udx_ver2 como o namespace padrão para os exemplos a seguir. As seções observam as diferenças em relação à versão 1 do UDX, e a referência de funções e agregados definidos pelo usuário da amostra contém exemplos de definições da versão 1 e da versão 2. Você pode continuar a criar funções UDX na versão 1 e funções novas na versão 2; ambas as funções executam em sistemas na liberação 6.0.x. No entanto, as funções da versão 1 funcionam nos sistemas Netezza Performance Server versão 5.0.x e posteriores e, portanto, podem ser mais portáteis para seus sistemas Netezza Performance Server.
Para implementar uma UDF, você cria um objeto de classe que é derivada da classe base do Udf. Continuando o exemplo customername:
#include "udxinc.h"
#include <string.h>

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

Cada UDF deve implementar os dois métodos a seguir:

  • O método instantiate() é chamado pelo mecanismo de tempo de execução para criar o objeto dinamicamente. A implementação estática deve ser fora da definição de classe. Na versão 2 do UDX, o método instantiate recebe um argumentoUdxInit *pInit), que permite o acesso à especificação de memória, à configuração de registro e ao ambiente UDX (consulte Ambiente UDX). O construtor deve ter um objeto UdxInit também e transmiti-lo para o construtor da classe base. O método instantiate cria um objeto do tipo de classe derivado usando o novo operador e retorna-o (Udf de tipo de classe base) para o mecanismo de tempo de execução. O mecanismo de tempo de execução exclui o objeto quando ele não for mais necessário. A seguir um exemplo do método instantiate versão 2 da API:
       #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);
    }
  • O método evaluate() é chamado uma vez para cada linha de dados durante a execução.
       #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);
    }
    

Você pode implementar os construtores e destruidores conforme necessário. Na API Versão 1, os construtores são opcionais. Na versão 2 da API, os construtores são necessários; você deve especificar um construtor mesmo se ele chamar o construtor da classe base, como no exemplo anterior. Algumas coisas comuns a serem incluídas nos construtores são rotinas de reserva de memória (visto que novo e excluir são relativamente caros) e configurar quaisquer estruturas que são necessárias para cálculo (por exemplo, configurando uma matriz para rotinas de criptografia).

No exemplo " customername, o UDF pega uma cadeia de caracteres e retorna o inteiro 1 se a cadeia começar com "Customer A"; caso contrário, retorna o inteiro 0. O código para o método de avaliação é o seguinte:
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
    }

No programa de amostra, a linha 4 declara e usa uma estrutura StringArg para transmitir o argumento para a UDF. Argumentos para UDFs são recuperados usando funções como StringArg. Se essa UDF teve um segundo argumento de sequência, o segundo argumento deve ser referenciado por StringArg(1). Para obter uma lista completa dos tipos de argumentos suportados e suas funções auxiliares associadas, consulte Referência da API do auxiliar de tipo de dados. Extrair as linhas 5 e 6, o comprimento e ponteiro de caractere (char*) da estrutura StringArg.

Observação: o programa de exemplo usa ' memcmp (e não ' strcmp) porque as estruturas StringArg não têm terminação nula (\0) em funções ou agregados definidos pelo usuário. Portanto, strcmp, strcpy, strlen, atol e outras funções que dependem da presença de um terminador nulo não funcionam. Se você precisar usar essas funções, você deve copiar a sequência em um buffer e anexar manualmente o terminador nulo.

A linha 11 usa uma macro UDX para retornar o valor calculado para o mecanismo do Netezza Performance Server. A macro NZ_UDX_RETURN_INT32 ajuda a confirmar que o valor de retorno é do tipo esperado. Para obter uma lista das macros de retorno disponíveis, consulte Macros de valor de retorno UDX.

Para usar a função, é necessário compilá-la e registrá-la como uma função disponível no sistema Netezza Performance Server.