Creare il file C++ per l'UDF

Per iniziare, utilizzare un qualsiasi editor di testo per creare il file C++. Il nome del file deve avere l'estensione " .cpp. Si consiglia di creare una directory come '/home/nz/udx_files come area per i file di codice UDX.

Il file C++ deve includere il file di intestazione 'udxinc.h, che contiene le dichiarazioni necessarie per le funzioni definite dall'utente e l'elaborazione sulle SPU.

#include "udxinc.h"
Inoltre, assicurarsi di dichiarare tutti i file di intestazione della libreria standard C++ che la funzione potrebbe richiedere. Se l'UDF richiede librerie condivise definite dall'utente, assicurarsi di annotare il nome delle librerie, perché saranno necessarie quando si registrerà l'UDF nel database. Ad esempio:
#include "udxinc.h"
#include <string.h>
Nota: Le librerie condivise definite dall'utente devono esistere nel database prima di poter registrare l'UDF e specificare tali librerie come dipendenze. È possibile registrare l'UDF senza specificare le dipendenze dalle librerie e, una volta aggiunte le librerie, utilizzare il comando ALTER FUNCTION per aggiornare la definizione dell'UDF con le dipendenze corrette. Per ulteriori informazioni sulle librerie condivise definite dall'utente, vedere Creare una libreria condivisa definita dall'utente.
Le classi e le funzioni UDX per la versione 2 dell'API sono definite in uno spazio dei nomi chiamato 'nz::udx_ver2. (Gli UDX della versione 1 dell'API utilizzano lo spazio dei nomi " nz::udx ) Il programma C++ deve fare riferimento allo spazio dei nomi corretto. Ad esempio:
#include "udxinc.h"
#include <string.h>
using namespace nz::udx_ver2;
Nota: questa sezione utilizza 'udx_ver2 come spazio dei nomi predefinito per gli esempi che seguono. Le sezioni segnalano le differenze con la versione 1 di UDX, mentre il riferimento alle funzioni e agli aggregati definiti dall'utente contiene esempi di definizioni della versione 1 e della versione 2. È possibile continuare a creare le funzioni UDX versione 1 e le nuove funzioni versione 2; entrambe le funzioni funzionano su sistemi con release 6.0.x. Tuttavia, le funzioni della versione 1 funzionano sui sistemi Netezza Performance Server release 5.0.x e successive e quindi potrebbero essere più portabili per i vostri sistemi Netezza Performance Server.
Per implementare una UDF, si crea un oggetto di classe derivato dalla classe base Udf. Continuando l'esempio del " customername:
#include "udxinc.h"
#include <string.h>

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

Ogni UDF deve implementare i due metodi seguenti:

  • Il metodo 'instantiate() viene richiamato dal motore di runtime per creare l'oggetto dinamicamente. L'implementazione statica deve essere esterna alla definizione della classe. Nella versione 2 di UDX, il metodo instantiate accetta un argomentoUdxInit *pInit), che consente di accedere alle specifiche di memoria, all'impostazione del registro e all'ambiente UDX (vedere Ambiente UDX). Il costruttore deve prendere anche un oggetto UdxInit e passarlo al costruttore della classe base. Il metodo instantiate crea un oggetto del tipo di classe derivata utilizzando l'operatore new e lo restituisce (come tipo di classe base Udf) al motore di runtime. Il motore di runtime cancella l'oggetto quando non è più necessario. Segue un esempio del metodo instantiate per la versione 2 dell'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);
    }
  • Il metodo 'evaluate() viene chiamato una volta per ogni riga di dati durante l'esecuzione.
       #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);
    }
    

È possibile implementare i costruttori e i distruttori come necessario. Nella versione 1 dell'API, i costruttori sono opzionali. Nella versione 2 dell'API, i costruttori sono obbligatori; è necessario specificare un costruttore anche se richiama solo il costruttore della classe base, come nell'esempio precedente. Alcune cose comuni da includere nei costruttori sono le routine di prenotazione della memoria (dato che new e delete sono relativamente costose) e la creazione di strutture necessarie per il calcolo (per esempio, la creazione di una matrice per le routine di crittografia).

Per l'esempio 'customername, l'UDF prende una stringa e restituisce il numero intero 1 se la stringa inizia con "Cliente A", altrimenti restituisce il numero intero 0. Segue il codice del metodo evaluate:
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
    }

Nel programma di esempio, la riga 4 dichiara e utilizza una struttura StringArg per passare l'argomento all'UDF. Gli argomenti delle UDF vengono recuperati utilizzando funzioni come 'StringArg. Se questa UDF avesse un secondo argomento stringa, il secondo argomento sarebbe referenziato da StringArg(1). Per un elenco completo dei tipi di argomenti supportati e delle funzioni helper associate, vedere Riferimento API helper dei tipi di dati. Le righe 5 e 6 estraggono la lunghezza e il puntatore al carattere (char*) dalla struttura StringArg.

Nota: Il programma di esempio utilizza 'memcmp (e non 'strcmp) perché le strutture StringArg non sono null-terminated (\0) nelle funzioni o negli aggregati definiti dall'utente. Pertanto, " strcmp, " strcpy, " strlen, " atol e altre funzioni che dipendono dalla presenza di un terminatore nullo non funzionano. Se è necessario utilizzare queste funzioni, è necessario copiare la stringa in un buffer e aggiungere manualmente il terminatore nullo.

La riga 11 utilizza una macro UDX per restituire il valore calcolato al motore di Netezza Performance Server. La macro NZ_UDX_RETURN_INT32 aiuta a confermare che il valore di ritorno è del tipo previsto. Per un elenco delle macro di ritorno disponibili, vedere Macro valore di ritorno UDX.

Per utilizzare la funzione, è necessario compilarla e registrarla come funzione disponibile sul sistema Netezza Performance Server.