C++ language shapers and sizers

This example uses the following file name: shaper.cpp

Code

The code in this example demonstrates both a shaper and sizer, each of which use the same code and perform essentially the same task. The code returns as output the given input. It does not demonstrate retrieving the literal fields, just the shaper/sizer functionality. This example uses handlers for both the function logic and the shaper logic. Note that you could choose not to use a handler for the shaper, but there is no reason to do so.
#include <nzaefactory.hpp>
using namespace nz::ae;
static int run(nz::ae::NzaeFunction *aeFunc);
static int doShaper(nz::ae::NzaeShaper *aeShaper);
int main(int argc, char * argv[])
{
NzaeApiGenerator helper;
// The following line is only needed if a launcher is not used
helper.setName("testcapi");
int i = 0;
while (i < 1) {
nz::ae::NzaeApi &api = helper.getApi(nz::ae::NzaeApi::ANY);
if (api.apiType == nz::ae::NzaeApi::FUNCTION) {
run(api.aeFunction);
i++;
}
else {
doShaper(api.aeShaper);
}
if (!helper.isRemote())
break;
}
return 0;
}
class MyHandler : public nz::ae::NzaeFunctionMessageHandler
{
public:
void evaluate(NzaeFunction& api, NzaeRecord &input, NzaeRecord &result) {
const NzaeMetadata& m = api.getMetadata();
nz::ae::NzaeField &field = input.get(0);
if (!field.isNull() ) {
nz::ae::NzaeField &f = result.get(0);
if (field.type() == NzaeDataTypes::NZUDSUDX_NUMERIC32 ||
field.type() == NzaeDataTypes::NZUDSUDX_NUMERIC64 ||
field.type() == NzaeDataTypes::NZUDSUDX_NUMERIC128)
{
NzaeNumericField &nf = (NzaeNumericField&)field;
if (m.getInputSize(0) != nf.precision() ||
m.getInputScale(0) != nf.scale()) {
NzaeNumeric128Field* np = nf.toNumeric128(38, 5);
f.assign(*np);
delete np;
}
else
f.assign(field);
}
else {
f.assign(field);
}
}
}
};
class MyHandler2 : public nz::ae::NzaeShaperMessageHandler
{
public:
void shaper(NzaeShaper& api){
const NzaeMetadata& m = api.getMetadata();
char name[2];
if (api.catalogIsUpper())
name[0] = 'I';
else
name[0] = 'i';
name[1] = 0;
if (m.getInputType(0) == NzaeDataTypes::NZUDSUDX_FIXED ||
m.getInputType(0) == NzaeDataTypes::NZUDSUDX_VARIABLE ||
m.getInputType(0) == NzaeDataTypes::NZUDSUDX_NATIONAL_FIXED ||
m.getInputType(0) == NzaeDataTypes::NZUDSUDX_NATIONAL_VARIABLE) {
api.addOutputColumnString(m.getInputType(0), name,
m.getInputSize(0));
}
else if (m.getInputType(0) == NzaeDataTypes::NZUDSUDX_NUMERIC128 ||
m.getInputType(0) == NzaeDataTypes::NZUDSUDX_NUMERIC64 ||
m.getInputType(0) == NzaeDataTypes::NZUDSUDX_NUMERIC32) {
api.addOutputColumnNumeric(m.getInputType(0), name, \
m.getInputSize(0), m.getInputScale(0));
}
else {
api.addOutputColumn(m.getInputType(0), name);
}
}
};
static int doShaper(nz::ae::NzaeShaper *aeShaper)
{
aeShaper->run(new MyHandler2());
return 0;
}
static int run(nz::ae::NzaeFunction *aeFunc)
{
aeFunc->run(new MyHandler());
return 0;
}

Note in the main that an API object must be retrieved in local mode, which gets both a function API and a shaper API (although not at the same time). Additionally, the code modifies the loop logic for remote mode so that the shaper is not incremented, allowing the same instance of the program to handle both a shaper and a function call in remote mode before exiting. Finally, it adds the shaper message handler.

Compilation

Use the standard compile:
$NZ_EXPORT_DIR/ae/utilities/bin/compile_ae --language cpp --template compile \
--exe shaperae --compargs "-g -Wall" --linkargs "-g" shaper.cpp \
--version 3

Registration

Register the example as a UDF and a UDTF:
$NZ_EXPORT_DIR/ae/utilities/bin/register_ae --sig "shaperae(VARARGS)" \
--return "table(ANY)" --language cpp --template udtf --exe shaperae \
--version 3
$NZ_EXPORT_DIR/ae/utilities/bin/register_ae --sig "sizerae(VARCHAR(ANY))" \
--return "varchar(ANY)" --language cpp --template udf --exe shaperae \
--version 3

Running

Run the query in nzsql:
SELECT sizerae('test');
SIZERAE
---------
test
(1 row)
SELECT * FROM TABLE WITH FINAL(shaperae('test'));
I
------
test
(1 row)
SELECT * FROM TABLE WITH FINAL(shaperae(1.1));
I
-----
1.1
(1 row)