C language shapers and sizers
This example uses the following file name: sstring.c
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.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "nzaeapis.h"
static int run(NZAE_HANDLE h);
static int runShaper(NZAESHP_HANDLE h);
int main(int argc, char * argv[])
{
if (nzaeIsLocal())
{
NzaeApi result;
char errorMessage[1050];
if (nzaeLocprotGetApi(&result, NZAE_LDK_VERSION,
errorMessage, sizeof(errorMessage)))
{
fprintf(stderr, "%s\n", errorMessage);
return -1;
}
if (result.apiType == NZAE_API_FUNCTION) {
run(result.handle.function);
nzaeClose(result.handle.function);
}
else {
runShaper(result.handle.shaper);
nzaeShpClose(result.handle.shaper);
}
}
else {
NZAECONPT_HANDLE hConpt = nzaeconptCreate();
if (!hConpt)
{
fprintf(stderr, "error creating connection point\n");
fflush(stderr);
return -1;
}
const char * conPtName = nzaeRemprotGetRemoteName();
if (!conPtName)
{
fprintf(stderr, "error getting connection point name\n");
fflush(stderr);
exit(-1);
}
if (nzaeconptSetName(hConpt, conPtName))
{
fprintf(stderr, "error setting connection point name\n");
fflush(stderr);
nzaeconptClose(hConpt);
return -1;
}
NzaeremprotInitialization args;
memset(&args, 0, sizeof(args));
args.ldkVersion = NZAE_LDK_VERSION;
args.hConpt = hConpt;
if (nzaeRemprotCreateListener(&args))
{
fprintf(stderr, "unable to create listener - %s\n", \
args.errorMessage);
fflush(stderr);
nzaeconptClose(hConpt);
return -1;
}
NZAEREMPROT_HANDLE hRemprot = args.handle;
NzaeApi api;
int i;
for (i = 0; i < 5; i++)
{
if (nzaeRemprotAcceptApi(hRemprot, &api))
{
fprintf(stderr, "unable to accept API - %s\n", \
nzaeRemprotGetLastErrorText(hRemprot));
fflush(stderr);
nzaeconptClose(hConpt);
nzaeRemprotClose(hRemprot);
return -1;
}
printf("testcapi: accepted a remote request\n");
fflush(stdout);
if (api.apiType == NZAE_API_FUNCTION) {
run(api.handle.function);
nzaeClose(api.handle.function);
}
else {
runShaper(api.handle.shaper);
nzaeShpClose(api.handle.shaper);
}
}
nzaeRemprotClose(hRemprot);
nzaeconptClose(hConpt);
}
return 0;
}
static int runShaper(NZAESHP_HANDLE h)
{
char name[2];
bool upper = true;
NzaeShpMetadata meta;
#define CHECK2(value) \
{ \
NzaeRcCode rc = value; \
if (rc) \
{ \
const char * format = "%s in %s at %d"; \
fprintf(stderr, format, \
nzaeShpGetLastErrorText(h), __FILE__, __LINE__); \
nzaeShpUserError(h, format, \
nzaeShpGetLastErrorText(h), __FILE__, __LINE__); \
exit(-1); \
} \
}
CHECK2(nzaeShpGetMetadata(h, &meta));
if (!meta.oneOutputRowRestriction)
CHECK2(nzaeShpSystemCatalogIsUpper(h, &upper));
if (upper)
name[0] = 'I';
else
name[0] = 'i';
name[1] = 0;
if (meta.inputTypes[0] == NZUDSUDX_FIXED ||
meta.inputTypes[0] == NZUDSUDX_VARIABLE ||
meta.inputTypes[0] == NZUDSUDX_NATIONAL_FIXED ||
meta.inputTypes[0] == NZUDSUDX_NATIONAL_VARIABLE) {
CHECK2(nzaeShpAddOutputColumnString(h, meta.inputTypes[0], name, \
meta.inputSizes[0]));
}
else if (meta.inputTypes[0] == NZUDSUDX_NUMERIC128 ||
meta.inputTypes[0] == NZUDSUDX_NUMERIC64 ||
meta.inputTypes[0] == NZUDSUDX_NUMERIC32) {
CHECK2(nzaeShpAddOutputColumnNumeric(h, meta.inputTypes[0], name, \
meta.inputSizes[0], meta.inputScales[0]));
}
else {
CHECK2(nzaeShpAddOutputColumn(h, meta.inputTypes[0], name));
}
CHECK2(nzaeShpUpdate(h));
}
static int run(NZAE_HANDLE h)
{
NzaeMetadata metadata;
if (nzaeGetMetadata(h, &metadata))
{
fprintf(stderr, "get metadata failed\n");
return -1;
}
#define CHECK(value) \
{ \
NzaeRcCode rc = value; \
if (rc) \
{ \
const char * format = "%s in %s at %d"; \
fprintf(stderr, format, \
nzaeGetLastErrorText(h), __FILE__, __LINE__); \
nzaeUserError(h, format, \
nzaeGetLastErrorText(h), __FILE__, __LINE__); \
exit(-1); \
} \
}
for (;;)
{
int i;
double result = 0;
NzaeRcCode rc = nzaeGetNext(h);
if (rc == NZAE_RC_END)
{
break;
}
NzudsData * input = NULL;
CHECK(nzaeGetInputColumn(h, 0, &input));
const char * opString;
if (input->isNull)
{
nzaeSetOutputNull(h,0);
}
else {
nzaeSetOutputColumn(h,0, input);
}
CHECK(nzaeOutputResult(h));
}
nzaeDone(h);
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). Note also that there is a new function to handle the shaper/sizer.
Compilation
Use the standard
compile:
$NZ_EXPORT_DIR/ae/utilities/bin/compile_ae --language system --version 3 \
--template compile sstring.c --exe shaperRegistration
Register the example as a UDF and a
UDTF:
$NZ_EXPORT_DIR/ae/utilities/bin/register_ae --language system --version 3 \
--template udtf --exe shaper --sig "tshaper_c(VARARGS)" \
--return "TABLE (ANY)"
$NZ_EXPORT_DIR/ae/utilities/bin/register_ae --language system --version 3 \
--template udf --exe shaper --sig "sizer_c(VARCHAR(ANY))" \
--return "VARCHAR(ANY)"Running
Run the query in nzsql. The code returns as output the given
input:
SELECT sizer_c('test');
SIZER_C
---------
test
(1 row)
SELECT * FROM TABLE WITH FINAL(tshaper_c('test'));
I
---
(1 row)
SELECT * FROM TABLE WITH FINAL(tshaper_c(1.1));
I
-----
1.1
(1 row)