Fonction scalaire en langage C++

L'exemple suivant montre une fonction scalaire simple qui additionne un ensemble de nombres. Cet exemple commence par la construction d'un AE simple. Il utilise le nom de fichier suivant : " applyopcpp.cpp

Coder

  1. Tirer sur l'interface C++. Ceci peut être réalisé en utilisant :
    #include <nzaefactory.h>
  2. Écrire un texte principal. Déterminer l'API à utiliser, dans ce cas une fonction. Pour ce faire, il est possible d'obtenir une connexion locale à l'AE ou une connexion à distance à l'AE. Cet exemple utilise une connexion AE locale. Deux interfaces peuvent être utilisées. L'un utilise le " NzaeFactory et l'autre le " NzaeApiGenerator. Dans cet exemple, nous utiliserons la classe du générateur car elle est plus simple et peut également être utilisée pour le mode à distance. Le programme devrait ressembler à ce qui suit :
    include <nzaefactory.hpp>
    using namespace nz::ae;
    int main(int argc, char * argv[])
    {
    NzaeApiGenerator helper;
    NzaeApi &api = helper.getApi(NzaeApi::FUNCTION);
    return 0;
    }
    Cette opération permet de récupérer une référence " NzaeApi qui contient un objet " NzaeFunction utilisable.
  3. Lorsque la fonction est disponible, ajouter un stub pour appeler la logique de la fonction :
    #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. Mettre en œuvre la fonction.

    Il existe deux façons de mettre en œuvre une fonction. Soit vous utilisez directement l'interface de l'objet " NzaeFunction, soit vous mettez en œuvre une classe dérivée " NzaeFunctionMessageHandler qui fournit une interface plus simple. Dans cet exemple, le gestionnaire de messages est utilisé. La seconde méthode fait l'objet d'un exemple séparé. Le gestionnaire de messages ne peut être utilisé que pour les fonctions qui renvoient une ligne de sortie par entrée. De plus, le gestionnaire couvre automatiquement certains détails de la gestion des erreurs.

    #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;
    }

    Dans cet exemple, la fonction run instancie l'objet handler, puis invoque la méthode run de la classe de fonction sur le handler. Le gestionnaire doit mettre en œuvre une méthode d'évaluation, qui prend une référence à la fonction ainsi que des références à l'enregistrement d'entrée et à l'enregistrement de sortie. Pour les fonctions normales, il n'y a qu'une seule colonne dans l'enregistrement de sortie. L'évaluation peut alors récupérer les champs de l'enregistrement d'entrée et les utiliser pour définir le champ de sortie. Ce code fournit une fonction de base, sans contrôle d'erreur, qui doit prendre comme premier argument soit le signe plus (+), soit l'astérisque (*), et comme arguments suivants des int32s Il additionne ou multiplie ensuite les int32s, en fonction de la valeur de l'argument spécifié, et renvoie le résultat sous la forme d'un double.

  5. La dernière étape de préparation du code ajoute le contrôle des erreurs et la prise en charge de types de données supplémentaires.
    #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;
    }

    Ce code garantit que le nombre et le type d'arguments d'entrée sont corrects et que le nombre et le type d'arguments de sortie sont corrects. Il prend en charge tous les types d'entiers, à savoir les flottants, les doubles et les numériques. Une fois le code terminé, il doit être compilé et enregistré.

Compilation

Compilez le code comme suit :
$NZ_EXPORT_DIR/ae/utilities/bin/compile_ae --language cpp --template compile \
--exe applyopcpp --compargs "-g -Wall" --linkargs "-g" applyopcpp.cpp \
--version 3

Les arguments précisent que vous utilisez le langage C++, version 3, avec le modèle compile, et que vous créez l'exécutable " applyopcpp". En outre, le compilateur et l'éditeur de liens utilisent l'argument supplémentaire fourni pour que l'exécutable " applyopcpp ait des symboles de débogage.

Enregistrement

Une fois compilé, le code est enregistré :
$NZ_EXPORT_DIR/ae/utilities/bin/register_ae --sig "applyop_cpp(VARARGS)" \
--return "double" --language cpp --template udf --exe applyopcpp \
--version 3

En cours d'exécution

Vous pouvez maintenant exécuter l'AE dans SQL :
SELECT applyop_cpp('+',1,2);
APPLYOP_CPP
-------------
3
(1 row)
Notez que dans le code, vous validez les types en utilisant " doOnce et envoyez une erreur en utilisant " NzaeException. L'exemple suivant déclenche une erreur :
SELECT applyop_cpp('-',1,2);
ERROR: unexpected operator -