Funzione scalare in linguaggio C++
L'esempio seguente mostra una semplice funzione scalare che somma un insieme di numeri. Questo esempio parte dall'inizio per costruire un semplice AE. Utilizza il seguente nome di file: 'applyopcpp.cpp
Codice
- Inserire l'interfaccia C++. In genere si può ottenere questo risultato utilizzando:
#include <nzaefactory.h>
- Scrivere un testo principale. Determinare un'API da utilizzare, in questo caso una funzione. Questo può essere ottenuto sia con una connessione AE locale che con una connessione AE remota. Questo esempio utilizza una connessione AE locale. È possibile utilizzare due interfacce. Uno utilizza il "
NzaeFactory
e l'altro il "NzaeApiGenerator
. In questo esempio, si utilizza la classe generatore, che è più semplice e può essere utilizzata anche per la modalità remota. Il programma dovrebbe apparire simile a:
Recupera un riferimento a 'include <nzaefactory.hpp> using namespace nz::ae; int main(int argc, char * argv[]) { NzaeApiGenerator helper; NzaeApi &api = helper.getApi(NzaeApi::FUNCTION); return 0; }
NzaeApi
che contiene un oggetto 'NzaeFunction
utilizzabile. - Quando la funzione è disponibile, aggiungere uno stub per richiamare la logica della funzione:
#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; }
- Implementare la funzione.
Esistono due modi per implementare una funzione. Si può usare direttamente l'interfaccia dell'oggetto '
NzaeFunction
o implementare una classe derivata da 'NzaeFunctionMessageHandler
che fornisce un'interfaccia più semplice. In questo esempio, viene utilizzato il gestore di messaggi. Il secondo metodo è trattato in un esempio separato. Il gestore di messaggi può essere utilizzato solo per le funzioni che restituiscono una riga di output per ogni input. Inoltre, il gestore copre automaticamente alcuni dettagli della gestione degli errori.#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; }
In questo esempio, la funzione run istanzia l'oggetto handler e poi invoca il metodo run della classe function sull'handler. Il gestore deve implementare un metodo evaluate, che prende un riferimento alla funzione e i riferimenti al record di input e al record di output. Per le funzioni normali, nel record di output è presente una sola colonna. La valutazione può quindi recuperare i campi dal record di input e utilizzarli per impostare il campo di output. Questo codice fornisce una funzione di base, senza controllo degli errori, che deve prendere come primo argomento il segno più (+) o l'asterisco (*) e come argomenti successivi degli int32s. Quindi somma o moltiplica gli int32s, in base al valore dell'argomento specificato, e restituisce il risultato come un doppio.
- La fase finale di preparazione del codice aggiunge il controllo degli errori e il supporto per altri tipi di dati.
#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; }
Questo codice garantisce il numero e il tipo corretto di argomenti di input e il numero e il tipo corretto di argomenti di output. Supporta tutti i tipi di numeri interi: float, double e numeric. Una volta completato, il codice deve essere compilato e registrato.
Compilazione
$NZ_EXPORT_DIR/ae/utilities/bin/compile_ae --language cpp --template compile \
--exe applyopcpp --compargs "-g -Wall" --linkargs "-g" applyopcpp.cpp \
--version 3
Gli argomenti specificano che si sta utilizzando il linguaggio C++, versione 3, con il template compile e che si sta creando l'eseguibile 'applyopcpp
. Inoltre, il compilatore e il linker utilizzano l'argomento aggiuntivo fornito, in modo che l'eseguibile 'applyopcpp
abbia i simboli di debug.
Registrazione
$NZ_EXPORT_DIR/ae/utilities/bin/register_ae --sig "applyop_cpp(VARARGS)" \
--return "double" --language cpp --template udf --exe applyopcpp \
--version 3
In esecuzione
SELECT applyop_cpp('+',1,2);
APPLYOP_CPP
-------------
3
(1 row)
doOnce
e si invia un errore utilizzando 'NzaeException
. L'esempio seguente genera un errore:SELECT applyop_cpp('-',1,2);
ERROR: unexpected operator -