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.)

Como ejemplo, el siguiente archivo UDF C++ denominado dir.cpp define tres funciones que se llaman OpenDir, ReadDir y CloseDir (basadas en las funciones LIBC), que se pueden utilizar para abrir un directorio local en el host, leer su contenido y cerrar la conexión al directorio. Estas funciones están definidas para que puedan llamarse desde NZPLSQL, y deben ejecutarse en modalidad desprotegida para realizar estas acciones. El archivo dir.cpp es el siguiente:
#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.

Puede compilar y registrar las tres UDF en el archivo dir.cpp utilizando los siguientes tres mandatos o utilizando los mandatos CREATE AND REPLACE FUNCTION:
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
A continuación, cree un procedimiento almacenado similar al siguiente procedimiento:
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;
El procedimiento de muestra llama a las nuevas UDF opendir(), readdir() y closedir() para operar en un directorio denominado /tmp/udx_known. Como ejemplo, si udx_known contiene el programa dir.cpp y los archivos de objeto de nzudxcompile, una llamada de muestra sp_listdirs01() devuelve la siguiente información:
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)
Si intenta ejecutar cualquiera de las UDFs ' OpenDir, ' ReadDir, o ' CloseDir en las SPUs o en DBOS, el sistema Netezza Performance Server informa de un error similar al siguiente mensaje:
DEV.SCHEMA(MYUSER)=> SELECT readdir(grp) FROM customers; 
ERROR:  readdir only supported in frontend