Creating the C++ file for a UDTF

To implement a UDTF, you create a class object that is derived from the Udtf base class. For example:
#include "udxinc.h"

using namespace nz::udx_ver2;

class parseNames : public Udtf {
public:
}
The parseNames UDTF takes an input table of strings fields that are separated by spaces or commas, and returns a table where each field of the requested string is output on its own row. As with other UDXs, you define the variables that are required for the UDTF algorithm at the class level. For example:
#include "udxinc.h"
using namespace nz::udx_ver2;

class parseNames : public Udtf {

private:
    char value[1000];
    int valuelen;
    int i;
public:
}
The parseNames UDTF uses the following variables:
value
A copy of the input parameter.
valuelen
The length of the input string.
i
A counter.
Each UDTF must implement the instantiate() and constructor method and two more UDTF-specific methods: newInputRow() and nextOutputRow(). An example of the methods and their purpose follows.
  • As with a UDSF, you call the instantiate() method to create the UDTF object dynamically. The instantiate method takes one argument (UdxInit *pInit), which enables access to the memory specification, the log setting, and the UDX environment (see UDX environment). The constructor must take a UdxInit object as well and pass it to the base class constructor. An example follows:
    #include "udxinc.h"
    using namespace nz::udx_ver2;
    
    class parseNames : public Udtf {
    private:
        char value[1000];
        int valuelen;
        int i;
    public:
        parseNames(UdxInit *pInit) : Udtf(pInit) {}
    
        static Udtf* instantiate(UdxInit*);
    };
    
    Udtf* parseNames::instantiate (UdxInit* pInit) {   
        return new parseNames(pInit); 
    }
  • For a UDTF, you use the newInputRow() method to perform initialization actions such as copying input arguments, initializing class variables, and managing situations such as null input variables. The method is called once for each input row. For the parseNames UDTF example, the following sample code copies the input list to the variable value, sets valuelen to the length of the input string, and initializes the variable i to zero:
        virtual void newInputRow() {
            StringArg *valuesa = stringArg(0);
            bool valuesaNull  = isArgNull(0);
            if (valuesaNull)
                valuelen = 0;
            else {
                if (valuesa->length >= 1000)
                  throwUdxException("Input value must be less than 1000 
    characters.");
                memcpy(value, valuesa->data, valuesa->length);
                value[valuesa->length] = 0;
                valuelen = valuesa->length;
            }
            i = 0;
        }
  • You use the nextOutputRow() method to create and return the next output row of the table. You should also detect whether there is more data to return and then return Done. The Db2® database engine calls this method at least once per input row. For example:
           virtual DataAvailable nextOutputRow() {
            if (i >= valuelen)
                   return Done;
            // save starting position of name
            int start = i;
            // scan string for next comma
            while ((i < valuelen) && value[i] != ',')
                i++;
            // return word
            StringReturn *rk = stringReturnColumn(0);
            if (rk->size < i-start)
              throwUdxException("Value exceeds return size");
            memcpy(rk->data, value+start, i-start);
            rk->size = i-start;
            i++;
            return MoreData;
        }

    As shown in the example, you create a column by using the appropriate column return type such as stringReturnColumn() or intReturnColumn() and you specify the position of the column such as 1, 2, 3, and so on. The return MoreData syntax indicates that there is another row to process. When the counter variable i reaches the end of the input string, there is no more data to process and nextOutputRow() returns Done.