C++ 语言标量函数

下面的示例展示了一个简单的标量函数,用于对一组数字求和。 本例从一开始就构建了一个简单的 AE。 它使用以下文件名:"applyopcpp.cpp

代码

  1. 拉入 C++ 界面。 这通常可以通过使用
    #include <nzaefactory.h>
  2. 写出主要内容。 确定要使用的 API,在本例中是一个函数。 这可以通过本地 AE 连接或远程 AE 连接来实现。 本例使用本地 AE 连接。 可使用两个接口。 一个使用 "NzaeFactory,另一个使用 "NzaeApiGenerator。 在本例中,使用生成器类,因为它更简单,也可用于远程模式。 程序应类似于
    include <nzaefactory.hpp>
    using namespace nz::ae;
    int main(int argc, char * argv[])
    {
    NzaeApiGenerator helper;
    NzaeApi &api = helper.getApi(NzaeApi::FUNCTION);
    return 0;
    }
    这将检索包含可用 NzaeFunction 对象的 NzaeApi 引用。
  3. 当函数可用时,添加调用函数逻辑的存根:
    #include <nzaefactory.hpp>
    using namespace nz::ae;
    static int run(nz::ae::NzaeFunction *aeFunc);
    int main(int argc, char * argv[])
    {
    NzaeApiGenerator helper;
    NzaeApi &api = helper.getApi(NzaeApi::FUNCTION);
    run(api.aeFunction);
    return 0;
    }
    static int run(NzaeFunction *aeFunc)
    {
    return 0;
    }
  4. 执行功能。

    实现函数有两种方法。 要么直接使用 "NzaeFunction对象接口,要么实现一个提供更简单接口的 "NzaeFunctionMessageHandler派生类。 本例中使用了消息处理程序。 第二种方法将在另一个示例中介绍。 消息处理程序仅适用于每个输入返回一行输出的函数。 此外,处理程序还会自动涵盖一些错误处理细节。

    #include <nzaefactory.hpp>
    using namespace nz::ae;
    static int run(nz::ae::NzaeFunction *aeFunc);
    int main(int argc, char * argv[])
    {
    NzaeApiGenerator helper;
    NzaeApi &api = helper.getApi(NzaeApi::FUNCTION);
    run(api.aeFunction);
    return 0;
    }
    class MyHandler : public NzaeFunctionMessageHandler
    {
    public:
    enum OperatorEnum
    {
    OP_ADD = 1,
    OP_MULT = 2
    } op;
    void evaluate(NzaeFunction& api, NzaeRecord &input, NzaeRecord &result) {
    double res = 0;
    NzaeField &field = input.get(0);
    if (field.isNull())
    throw NzaeException("first input column may not be null");
    NzaeStringField &sf = (NzaeStringField&) input.get(0);
    std::string strop = (std::string)sf;
    if (strop == "+")
    op = OP_ADD;
    else if (strop == "*") {
    op = OP_MULT;
    res = 1;
    }
    else
    throw NzaeException(NzaeException::format("unexpected \
    operator %s", strop.c_str()));
    for (int i=1 ; i < input.numFields(); i++) {
    NzaeField &inf = input.get(i);
    if (inf.isNull())
    continue;
    double temp = 0;
    bool ignore = false;
    switch (inf.type()) {
    case NzaeDataTypes::NZUDSUDX_INT32:
    {
    NzaeInt32Field &sf = (NzaeInt32Field&)input.get(i);
    temp = (int32_t)sf;
    break;
    }
    default:
    ignore = true;
    // ignore
    break;
    }
    if (!ignore) {
    if (op == OP_ADD)
    res += temp;
    else
    res *= temp;
    }
    }
    NzaeDoubleField &f = (NzaeDoubleField&)result.get(0);
    f = res;
    }
    };
    static int run(NzaeFunction *aeFunc)
    {
    aeFunc->run(new MyHandler());
    return 0;
    }

    在本例中,运行函数实例化了处理程序对象,然后在处理程序上调用函数类的运行方法。 处理程序必须实现一个求值方法,该方法需要函数的引用以及输入记录和输出记录的引用。 对于普通函数,输出记录中只有一列。 然后,评估程序就可以从输入记录中检索字段,并利用这些字段设置输出字段。 这段代码提供了一个基本的非错误检查函数,它的第一个参数是字符串加号 (+) 或字符串星号 (*),其后的参数是int32s。 然后,它会根据指定的参数值将int32s 相加或相乘,并将结果以 double 的形式返回。

  5. 最后的代码准备步骤增加了错误检查功能和对其他数据类型的支持。
    #include <nzaefactory.hpp>
    using namespace nz::ae;
    static int run(nz::ae::NzaeFunction *aeFunc);
    int main(int argc, char * argv[])
    {
    NzaeApiGenerator helper;
    NzaeApi &api = helper.getApi(NzaeApi::FUNCTION);
    run(api.aeFunction);
    return 0;
    }
    class MyHandler : public NzaeFunctionMessageHandler
    {
    public:
    MyHandler() {
    m_Once = false;
    }
    enum OperatorEnum
    {
    OP_ADD = 1,
    OP_MULT = 2
    } op;
    void doOnce(NzaeFunction& api) {
    const NzaeMetadata& meta = api.getMetadata();
    if (meta.getOutputColumnCount() != 1 ||
    meta.getOutputType(0) != NzaeDataTypes::NZUDSUDX_DOUBLE) {
    throw NzaeException("expecting one output column of type double");
    }
    if (meta.getInputColumnCount() < 1) {
    throw NzaeException("expecting at least one input column");
    }
    if (meta.getInputType(0) != NzaeDataTypes::NZUDSUDX_FIXED &&
    meta.getInputType(0) != NzaeDataTypes::NZUDSUDX_VARIABLE) {
    throw NzaeException("first input column expected to be a string \
    type");
    }
    m_Once = true;
    }
    void evaluate(NzaeFunction& api, NzaeRecord &input, NzaeRecord &result) {
    if (!m_Once)
    doOnce(api);
    double res = 0;
    NzaeField &field = input.get(0);
    if (field.isNull())
    throw NzaeException("first input column may not be null");
    NzaeStringField &sf = (NzaeStringField&) input.get(0);
    std::string strop = (std::string)sf;
    if (strop == "+")
    op = OP_ADD;
    else if (strop == "*") {
    op = OP_MULT;
    res = 1;
    }
    else
    throw NzaeException(NzaeException::format("unexpected operator \
    %s", strop.c_str()));
    for (int i=1 ; i < input.numFields(); i++) {
    NzaeField &inf = input.get(i);
    if (inf.isNull())
    continue;
    double temp = 0;
    bool ignore = false;
    switch (inf.type()) {
    case NzaeDataTypes::NZUDSUDX_INT8:
    {
    NzaeInt8Field &sf = (NzaeInt8Field&)input.get(i);
    temp = (int8_t)sf;
    break;
    }
    case NzaeDataTypes::NZUDSUDX_INT16:
    {
    NzaeInt16Field &sf = (NzaeInt16Field&)input.get(i);
    temp = (int16_t)sf;
    break;
    }
    case NzaeDataTypes::NZUDSUDX_INT32:
    {
    NzaeInt32Field &sf = (NzaeInt32Field&)input.get(i);
    temp = (int32_t)sf;
    break;
    }
    case NzaeDataTypes::NZUDSUDX_INT64:
    {
    NzaeInt64Field &sf = (NzaeInt64Field&)input.get(i);
    temp = (int64_t)sf;
    break;
    }
    case NzaeDataTypes::NZUDSUDX_FLOAT:
    {
    NzaeFloatField &sf = (NzaeFloatField&)input.get(i);
    temp = (float)sf;
    break;
    }
    case NzaeDataTypes::NZUDSUDX_DOUBLE:
    {
    NzaeDoubleField &sf = (NzaeDoubleField&)input.get(i);
    temp = (double)sf;
    break;
    }
    case NzaeDataTypes::NZUDSUDX_NUMERIC32:
    case NzaeDataTypes::NZUDSUDX_NUMERIC64:
    case NzaeDataTypes::NZUDSUDX_NUMERIC128:
    {
    NzaeNumericField &sf = (NzaeNumericField&)input.get(i);
    temp = (double)sf;
    break;
    }
    default:
    ignore = true;
    // ignore
    break;
    }
    if (!ignore) {
    if (op == OP_ADD)
    res += temp;
    else
    res *= temp;
    }
    }
    NzaeDoubleField &f = (NzaeDoubleField&)result.get(0);
    f = res;
    }
    bool m_Once;
    };
    static int run(NzaeFunction *aeFunc)
    {
    aeFunc->run(new MyHandler());
    return 0;
    }

    该代码可确保输入参数的数量和类型以及输出参数的数量和类型正确无误。 它支持所有整数类型,包括浮点、双和数值。 代码完成后,必须进行编译和注册。

编译

编译代码如下:
$NZ_EXPORT_DIR/ae/utilities/bin/compile_ae --language cpp --template compile \
--exe applyopcpp --compargs "-g -Wall" --linkargs "-g" applyopcpp.cpp \
--version 3

参数说明您使用的是 C++ 语言第 3 版,使用模板编译,并创建了可执行文件 "applyopcpp。 此外,编译器和链接器还会使用所提供的附加参数,以便 "applyopcpp可执行文件具有调试符号。

注册

编译后,注册代码:
$NZ_EXPORT_DIR/ae/utilities/bin/register_ae --sig "applyop_cpp(VARARGS)" \
--return "double" --language cpp --template udf --exe applyopcpp \
--version 3

正在运行

现在可以在 SQL 中运行 AE:
SELECT applyop_cpp('+',1,2);
APPLYOP_CPP
-------------
3
(1 row)
请注意,在代码中,您使用 "doOnce验证类型,并使用 "NzaeException发送错误信息。 以下示例会引发错误:
SELECT applyop_cpp('-',1,2);
ERROR: unexpected operator -