Fonction scalaire en langage C++ (mode distant)
Cet exemple utilise le nom de fichier suivant :
applyopcpp.cpp
Coder
Le code de cet exemple montre que, moyennant quelques modifications mineures, ce programme fonctionne en mode distant :
Le changement se situe au niveau de l'essentiel. Le nom de la connexion AE distante requise, testcapi, est défini, puis une boucle est ajoutée autour de getAPI afin qu'il soit appelé deux fois. Ce code fonctionne comme un AE local et gère deux itérations comme un AE distant.
#include <nzaefactory.hpp>
using namespace nz::ae;
static int run(nz::ae::NzaeFunction *aeFunc);
int main(int argc, char * argv[])
{
NzaeApiGenerator helper;
// The following line is only needed if a launcher is not used
helper.setName("testcapi");
for (int i=0; i < 2; i++) {
nz::ae::NzaeApi &api = helper.getApi(nz::ae::NzaeApi::FUNCTION);
run(api.aeFunction);
if (!helper.isRemote())
break;
}
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;
}
Compilation
Utiliser la compilation standard, comme en mode local :
$NZ_EXPORT_DIR/ae/utilities/bin/compile_ae --language cpp --template compile \
--exe applyopcpp --compargs "-g -Wall" --linkargs "-g" applyopcpp.cpp \
--version 3
Enregistrement
$NZ_EXPORT_DIR/ae/utilities/bin/register_ae --sig "rem_applyop_cpp(VARARGS)" \
--return "double" --language cpp --template udf --exe applyopcpp \
--version 3 --remote --rname testcapi$NZ_EXPORT_DIR/ae/utilities/bin/register_ae --sig "rem_applyop_launch(int8)" \
--return "TABLE(aeresult varchar(255))" --language cpp --template udtf \
--exe applyopcpp --version 3 --remote --launch --rname testcapiÀ l'exception de --rname, --exe et de la partie nom de --sig, tous les lanceurs ressemblent à ce qui précède. Dans ce cas, il s'agit d'un UDTF, puisque c'est l'interface de tous les lanceurs. La valeur de --rname doit correspondre au nom dans le code.
En cours d'exécution
Pour exécuter l'AE en mode distant, l'exécutable est exécuté en tant que "serveur" Dans ce cas, il ne traite que les requêtes exécutées sur l'hôte. En général, les AE sont également lancés sur les SPU. Démarrer une instance sur l'hôte :
SELECT * FROM TABLE WITH FINAL(rem_applyop_launch(0));
AERESULT
-------------------------------------------------------------------------------
tran: 7192 DATA slc: 0 hardware: 0 machine: spubox1 process: 8306 thread: 8306
(1 row)
Notez qu'une syntaxe différente est utilisée pour invoquer le lanceur de style de fonction de table. Il s'agit de la syntaxe utilisée pour appeler tout AE basé sur l'UDTF. Exécutez maintenant l'AE :
SELECT rem_applyop_cpp('+', 4,5,1.1);
REM_APPLYOP_CPP
-----------------
10.1
(1 row)
Enfin, provoquer une erreur :
SELECT rem_applyop_cpp(1);
ERROR: first input COLUMN expected TO be a string type