Create the C++ file for the UDTF
To begin, use any text editor to create your C++ file. The file name must have a .cpp extension. You might want to create a directory such as /home/nz/udx_files as your area for UDX code files.
Your C++ file must include the udxinc.h header file, which contains the required declarations for user-defined table functions and processing on the SPUs.
#include "udxinc.h"
#include "udxinc.h"
#include <string.h>User-defined shared libraries must exist in the database before you can register the UDTF and specify those libraries as dependencies. You can register the UDTF without specifying any library dependencies, and after the libraries are added, use the ALTER FUNCTION command to update the UDTF definition with the correct dependencies. For more information about user-defined shared libraries, see Create a user-defined shared library.
nz::udx_ver2. Your C++ program
must reference the correct namespace. For example:#include "udxinc.h"
using namespace nz::udx_ver2;#include "udxinc.h"
using namespace nz::udx_ver2;
class parseNames : public Udtf {
public:
}#include "udxinc.h"
using namespace nz::udx_ver2;
class parseNames : public Udtf {
private:
char value[1000];
int valuelen;
int i;
public:
}- The
valuevariable contains a copy of the input parameter. - The
valuelenvariable contains the length of the input string. - The
ivariable is a counter.
- As with UDFs, you call the instantiate() method
to create the UDTF object dynamically, In UDX version 2, 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
valuelento the length of the input string, and initializes the variableito 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.
Netezza Performance Server calls this method at least
once per input row. Sample code follows:
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
ireaches the end of the input string, there is no more data to process and nextOutputRow() returns Done. - If your UDTF supports the TABLE WITH FINAL syntax, you use the nextEoiOutputRow() method
at least once after the end of the input to process and output all
the data. The base class has a default implementation of this method
that returns no rows when called. It is similar to nextOutputRow() except
that newInputRow() is not called before it. A sample
method follows:
virtual DataAvailable nextEoiOutputRow() return Done; }