UDXs pour étendre le langage NZPLSQL
Les utilisateurs créent des procédures stockées en écrivant des applications qui utilisent le langage NZPLSQL. NZPLSQL est un langage interprété basé sur le langage PL/pgSQL de Postgres et conçu pour l'environnement hôte.
Vous pouvez étendre le langage NZPLSQL avec la fonctionnalité UDF C++ des fonctions définies par l'utilisateur. Ces UDF doivent être invoqués en utilisant un SQL structuré de manière à garantir que les UDF s'exécutent toujours sur l'hôte Netezza Performance Server à l'intérieur de Postgres. Comme les UDF sont limités à l'hôte, ils peuvent tirer parti de l'ensemble des fonctions LIBC, des caractéristiques et des autres bibliothèques standard qui ne sont pas présentes sur les SPU basées sur le Nucleus. Ces UDF doivent également être enregistrés pour fonctionner en mode non clôturé.
Les fonctions de la bibliothèque d'exécution C décrivent l'ensemble recommandé de bibliothèques prises en charge par le LIBC pour les UDF qui peuvent être exécutées sur les SPU et sur l'hôte. Il s'agit d'un sous-ensemble de la bibliothèque LIBC complète.
Pour vous assurer que vos UDF d'extension linguistique ne s'exécutent que sur l'hôte Netezza Performance Server au sein de Postgres, vous utilisez la fonction 'getCurrentLocus() Cette fonction détecte le lieu d'exécution de l'UDF. Concevez vos UDF de manière à ce qu'ils lèvent une exception si la valeur de retour n'est pas UDX_LOCUS_POSTGRES. (Les autres valeurs possibles sont UDX_LOCUS_DBOS ou 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;
}L'exemple de fichier " dir.cpp stocke plusieurs pointeurs dans un champ int32. Si le système d'exploitation Netezza Performance Server passe à une version 64 bits à l'avenir, ces pointeurs devront utiliser int64 à la place.
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