Create the C++ file for the UDF
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 functions and processing on the SPUs.
#include "udxinc.h"
#include "udxinc.h"
#include <string.h>
nz::udx_ver2
. (The API version
1 UDXs use the nz::udx
namespace.) Your C++ program
must reference the correct namespace. For example:#include "udxinc.h"
#include <string.h>
using namespace nz::udx_ver2;
udx_ver2
as the
default namespace for the examples that follow. The sections note
the differences with UDX version 1, and Sample user-defined functions and aggregates reference contains
examples of version 1 and version 2 definitions. You can continue
to create UDX version 1 functions and new version 2 functions; both
functions run on release 6.0.x systems. However, the version 1 functions
work on Netezza Performance Server release
5.0.x and later systems and thus might be more portable for your Netezza Performance Server systems.customername
example:#include "udxinc.h"
#include <string.h>
using namespace nz::udx_ver2;
class CCustomerName: public nz::udx_ver2::Udf
{
public:
};
Each UDF must implement the following two methods:
- The instantiate() method is called by the runtime
engine to create the object dynamically. The static implementation
must be outside the class definition. 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. The instantiate method creates an object
of the derived class type by using the new operator and returns it
(as base class type Udf) to the runtime engine. The runtime engine
deletes the object when it is no longer needed. An example of the
instantiate method for API version 2 follows:
#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); }
- The evaluate() method is called once for each
row of data during execution.
#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); }
You can implement constructors and destructors as necessary. In API Version 1, constructors are optional. In API version 2, constructors are required; you must specify a constructor even if it only invokes the base class constructor, as in the previous example. Some common things to include in constructors are memory reservation routines (since new and delete are relatively expensive), and setting up any structures that are needed for computation (for example, setting up a matrix for encryption routines).
customername
example, the UDF takes a
string and returns the integer 1 if the string starts with “Customer
A”, otherwise it returns the integer 0. The code for the evaluate
method follows: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
}
In the sample program, line 4 declares and uses a StringArg structure to pass the argument to the UDF. Arguments to UDFs are retrieved by using functions such as StringArg. If this UDF took a second string argument, the second argument would be referenced by StringArg(1). For a complete list of argument types that are supported and their associated helper functions, see Data type helper API reference. Lines 5 and 6 extract the length and character pointer (char*) from the StringArg structure.
Line 11 uses a UDX macro to return the computed value to the Netezza Performance Server engine. The NZ_UDX_RETURN_INT32 macro helps to confirm that the return value is of the expected type. For a list of the available return macros, see UDX return value macros.
To use the function, you must compile and register it as an available function on the Netezza Performance Server system.