为 UDTF 创建 C++ 文件

首先,使用任何文本编辑器创建 C++ 文件。 文件名的扩展名必须是 ".cpp。 您可能需要创建一个目录,如 "/home/nz/udx_files,作为 UDX 代码文件的存放区域。

您的 C++ 文件必须包含 "udxinc.h头文件,其中包含用户定义表函数和 SPU 处理所需的声明。

#include "udxinc.h"
此外,请确保声明了表格函数可能需要的任何标准 C++ 库头文件。 如果您的 UDTF 需要任何用户定义的共享库,请务必记下这些库的名称,因为您在数据库中注册 UDTF 时必须指定这些库。 例如:
#include "udxinc.h"
#include <string.h>

在注册 UDTF 并将这些库指定为依赖库之前,数据库中必须存在用户定义的共享库。 您可以在不指定任何库依赖关系的情况下注册 UDTF,并在添加库后使用 ALTER FUNCTION 命令用正确的依赖关系更新 UDTF 定义。 有关用户定义共享库的更多信息,请参阅创建用户定义共享库

API 第 2 版的 UDX 类和函数定义在名为 "nz::udx_ver2的命名空间中。 您的 C++ 程序必须引用正确的名称空间。 例如:
#include "udxinc.h"

using namespace nz::udx_ver2;
要实现 UDTF,请创建从 Udtf 基类派生的类对象。 例如:
#include "udxinc.h"

using namespace nz::udx_ver2;

class parseNames : public Udtf {
public:
}
parseNames UDTF 接受字符串字段(以空格或逗号分隔)的输入表,并返回一个表,其中,所请求字符串的每个字段都在自己的行上输出。 与其他 UDX 一样,您可以在类级别定义 UDTF 算法所需的变量。 例如:
#include "udxinc.h"
using namespace nz::udx_ver2;

class parseNames : public Udtf {

private:
    char value[1000];
    int valuelen;
    int i;
public:
}
parseNames UDTF 使用以下变量:
  • value变量包含输入参数的副本。
  • valuelen变量包含输入字符串的长度。
  • i变量是一个计数器。
每个 UDTF 都必须实现 instantiate() 和构造方法,以及另外两个特定于 UDTF 的方法:newInputRow()nextOutputRow()nextEoiOutputRow()UTF 专用方法是可选的。 以下是方法及其用途的示例。
  • 与 UDF 一样,调用 "instantiate()方法动态创建 UDTF 对象。在 UDX 版本 2 中,"instantiate方法需要一个参数UdxInit *pInit),它允许访问内存规范、日志设置和 UDX 环境(参见UDX 环境)。 构造函数还必须接受 UdxInit 对象,并将其传递到基类构造函数。 示例如下:
       #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); 
    }
  • 对于 UDTF,您可以使用 newInputRow() 方法来执行初始化操作,例如复制输入自变量,初始化类变量以及管理输入变量为 null 之类的情况。 此方法针对每个输入行调用一次。 对于 parseNames UDTF 示例,以下样本代码将输入列表复制到变量值,将 valuelen 设置为输入字符串的长度,并将变量 i 初始化为零:
        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;
        }
  • 您可使用 nextOutputRow() 方法来创建并返回表的下一个输出行。 您还应该检测是否有更多数据要返回,然后返回 Done。 Netezza Performance Server对每个输入行至少调用一次该方法。 代码示例如下:
           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;
        }

    如示例所示,您可使用相应的列返回类型(例如,stringReturnColumn()intReturnColumn())来创建列,并指定该列的位置,例如,1、2、3 等等。 return MoreData 语法表示还有要处理的行。 当计数器变量 i 到达输入字符串的末尾时,表示没有其他要处理的数据,此时 nextOutputRow() 返回 Done。

  • 如果您的 UDTF 支持 TABLE WITH FINAL 语法,您至少要在输入结束后使用一次 "nextEoiOutputRow()方法来处理和输出所有数据。 基类有一个此方法的默认实现,调用时不会返回任何行。 它与 "nextOutputRow()相似,只是在它之前不调用 "newInputRow()。 下面是一个示例方法:
           virtual DataAvailable nextEoiOutputRow()
            return Done;
        }