UDX para ampliar el lenguaje NZPLSQL
Los usuarios crean procedimientos almacenados escribiendo aplicaciones que utilizan el lenguaje NZPLSQL. NZPLSQL es un lenguaje interpretado que se basa en el lenguaje PL/pgSQL Postgres y que está diseñado para el entorno host.
Puede ampliar el lenguaje NZPLSQL con la funcionalidad UDF de C++ de la característica de funciones definidas por el usuario. Estas UDF deben invocarse utilizando SQL estructurado de forma que se garantice que las UDF se ejecutan siempre en el host de Netezza Performance Server dentro de Postgres. Ya que las UDF están restringidas al host, pueden aprovecharse del rango completo de funciones, características y otras bibliotecas estándar de LIBC que no están presentes en las SPU basados en Nucleus. Estas UDF también deben registrarse para ejecutarse en modalidad desprotegida.
Funciones de biblioteca en tiempo de ejecución C describe el conjunto recomendado de bibliotecas compatibles con LIBC para las UDF que pueden ejecutarse en las SPU y en el host. Esto es un subconjunto de conjunto de bibliotecas LIBC completo.
Para garantizar que sus UDF de extensión de idioma se ejecutan únicamente en el host de Netezza Performance Server dentro de Postgres, utilice la función ' getCurrentLocus(). Esta función detecta el punto o lugar de ejecución de la UDF. Diseñe las UDF para emitir una excepción si el valor de retorno es otro distinto a UDX_LOCUS_POSTGRES. (Los otros valores posibles son UDX_LOCUS_DBOS o UDX_LOCUS_SPU.)
#include <udxinc.h>
#include <dirent.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
using namespace nz::udx;
class OpenDir : public Udf
{
public:
Udf * instantiate();
ReturnValue evaluate() {
if (getCurrentLocus() != UDX_LOCUS_POSTGRES)
throwUdxException("opendir only supported in frontend");
#ifndef FOR_SPU
if (isArgNull(0))
NZ_UDX_RETURN_NULL();
StringArg *arg = stringArg(0);
char path[2048];
memcpy(path, arg->data, arg->length);
path[arg->length] = 0;
DIR *dir = opendir(path);
if (dir == NULL) {
char format[2500];
sprintf(format, "Can't open dir %s: %s", path,
strerror(errno));
throwUdxException(format);
}
NZ_UDX_RETURN_INT32((int32)dir);
#endif
}
};
Udf* OpenDir::instantiate()
{
return new OpenDir;
}
class ReadDir : public Udf
{
public:
Udf * instantiate();
ReturnValue evaluate() {
if (getCurrentLocus() != UDX_LOCUS_POSTGRES)
throwUdxException("readdir only supported in frontend");
#ifndef FOR_SPU
if (isArgNull(0))
NZ_UDX_RETURN_NULL();
int32 arg = int32Arg(0);
DIR *dir = (DIR*)arg;
struct dirent *dp;
dp = readdir(dir);
if (dp == NULL)
NZ_UDX_RETURN_NULL();
StringReturn* info = stringReturnInfo();
memcpy(info->data, dp->d_name, strlen(dp->d_name));
info->size = strlen(dp->d_name);
NZ_UDX_RETURN_STRING(info);
#endif
}
};
Udf* ReadDir::instantiate()
{
return new ReadDir;
}
class CloseDir : public Udf
{
public:
Udf * instantiate();
ReturnValue evaluate() {
if (getCurrentLocus() != UDX_LOCUS_POSTGRES)
throwUdxException("closedir only supported in frontend");
#ifndef FOR_SPU
if (isArgNull(0))
NZ_UDX_RETURN_NULL();
int32 arg = int32Arg(0);
DIR *dir = (DIR*)arg;
closedir(dir);
NZ_UDX_RETURN_BOOL(true);
#endif
}
};
Udf* CloseDir::instantiate()
{
return new CloseDir;
}El archivo dir.cpp de muestra almacena varios punteros en un campo int32. Si el sistema operativo Netezza Performance Server cambia a una versión de 64 bits en el futuro, estos punteros tendrían que cambiar para utilizar int64 en su lugar.
nzudxcompile dir.cpp --sig "opendir(varchar(any))" --return int4
--class OpenDir --unfenced
nzudxcompile dir.cpp --sig "readdir(int4)" --return "varchar(512)"
--class ReadDir --unfenced
nzudxcompile dir.cpp --sig "closedir(int4)" --return "bool"
--class CloseDir --unfenced
DEV.SCHEMA(MYUSER)=> CREATE OR REPLACE PROCEDURE sp_listdirs01() RETURNS BOOL
LANGUAGE NZPLSQL AS
BEGIN_PROC
DECLARE
dirp int4;
nm varchar(512);
cl bool;
dir varchar(1024);
num int4;
r record;
BEGIN
select count(*) INTO num from _t_object where upper(objname) =
'SORTER' and objclass = 4905 and objdb = current_db;
IF num = 1 THEN
DROP TABLE SORTER;
END IF;
CREATE TABLE SORTER (grp int4, name varchar(2000));
dir := '/tmp/udx_known';
dirp := opendir(dir);
LOOP
nm = readdir(dirp);
exit when nm is null;
EXECUTE IMMEDIATE 'INSERT INTO SORTER VALUES (1, ' ||
quote_literal(nm) || ')';
END LOOP;
FOR r in SELECT name from sorter order by name LOOP
RAISE NOTICE 'got %/%', dir, r.name;
END LOOP;
cl = closedir(dirp);
DROP TABLE SORTER;
RETURN cl;
EXCEPTION WHEN OTHERS THEN
IF dirp is not NULL THEN
cl = closedir(dirp);
RETURN cl;
END IF;
END;
END_PROC;DEV.SCHEMA(MYUSER)=> CALL sp_listdirs01();
call sp_listdirs01();
NOTICE: got /tmp/udx_known/.
NOTICE: got /tmp/udx_known/..
NOTICE: got /tmp/udx_known/dir.cpp
NOTICE: got /tmp/udx_known/dir.o_diab_ppc
NOTICE: got /tmp/udx_known/dir.o_ppc
NOTICE: got /tmp/udx_known/dir.o_x86
SP_LISTDIRS01
---------------
t
(1 row)
DEV.SCHEMA(MYUSER)=> SELECT readdir(grp) FROM customers;
ERROR: readdir only supported in frontend