 | Nível: Intermediário Josef Klitsch, IT Specialist, IBM
09/Jul/2009
Por meio de exemplos, aprenda a criar uma user-defined function (UDF) externa no DB2® para z/OS®
que pode ser lida por arquivos z/OS Unix® System Services (USS) e conjuntos de dados z/OS. Então,
será possível usar as funções SQL integradas existentes e suas próprias UDFs para executar
manipulação de dados nas informações armazenadas nos conjuntos de dados e arquivos. Também
é possível expor essas instruções SQL "de leitura de arquivo" como IBM Data Web Services.
Desse modo os conjuntos de dados e arquivos ficam disponíveis para operações de serviços da Web.
Visão Geral
Com os IBM Data Web Services, é possível integrar facilmente as operações de banco de dados em uma Service Oriented Architecture (SOA) transformando operações SQL únicas em serviços da Web.
As operações SQL válidas que podem ser transformadas incluem invocações de user-defined function (UDF) iniciadas por SQL DML.
Este artigo fornece uma introdução ao DB2 para z/OS UDFs externas e mostra como elas ajudam a integrar as informações dos arquivos e conjuntos de dados z/OS aos Data Web Services.
Depois, o artigo mostra:
-
Exemplos de UDFs externas escritas em C e implementadas em DB2 para z/OS, que leem arquivos z/OS UNIX System Services (USS) e conjuntos de dados z/OS
-
Como integrar os resultados de UDF às operações SQL
-
Como usar a funcionalidade do SQL para mapear a estrutura de campo de registro de arquivo para colunas da tabela de resultados
Ao repassar o programa ReadFile C, você talvez tenha uma agradável surpresa ao ver como tarefas complexas
de programação, como alocação de conjuntos de dados dinâmicos e seleção de método de acesso QSAM e VSAM,
podem ser gerenciadas de forma transparente pelo ambiente de tempo de execução z/OS XL C/C++.
O artigo demonstra então como usar o IBM Optim Development Studio (ex-Data Studio Developer) para expor instruções SQL que leem conjuntos de dados z/OS e informações de arquivos USS como serviços da Web.
Pré-Requisitos
Este artigo presume que você saiba o que são IBM Data Web Services e que esteja familiarizado com noções básicas
de uso do IBM Optim Development Studio (ou Data Studio, ou Data Studio Developer) para criação, teste e
implementação de IBM Data Web Services. Se você não conhece algum desses tópicos, consulte a seção Recursos para saber os links para informações adicionais.
Também seria bom ler "Fazendo Chamadas
ao Sistema Operacional a partir do SQL".
Este artigo fornece informações úteis sobre como ler arquivos a partir de user-defined functions externas.
Introdução às user-defined functions do DB2 para z/OS
Uma user-defined function (UDF) é uma extensão da linguagem SQL e é similar ao programa ou função de linguagem
de host. As UDFs são invocadas de dentro de instruções SQL, fornecendo assim integração com o SQL DML. O DB2 para
z/OS suporta os seguintes tipos de UDFs:
-
UDFs originadas se baseiam em user-defined functions existentes e em funções integradas.
-
SQL UDFs são definidas em SQL e podem retornar uma expressão SQL.
-
UDFs externas podem ser escritas em diferentes linguagens de programação, incluindo
Assembler, C, COBOL, PL/1 e Java®.
As UDFs se dividem em duas categorias:
-
As funções escalares definidas pelo usuário retornam uma resposta de valor único
toda vez que são invocadas. As funções em tabela definidas pelo usuário retornam uma tabela para a instrução SQL
invocada. A funcionalidade de UDF de tabela no DB2 para z/OS só está disponível para UDFs externas.
UDFs externas de DB2 para z/OS
As UDFs externas de DB2 para z/OS podem ser desenvolvidas como função de tabela ou escalares.
Elas têm muitos atributos em comum com os procedimentos externos armazenados.
Como os procedimentos externos armazenados elas:
-
São aplicativos do lado do servidor que podem ser escritos em diferentes linguagens de programação
-
Podem acessar recursos não DB2, como conjuntos de dados QSAM e VSAM, filas de mensagens, programas CICS, transações do IMS e bancos de dados como qualquer outro programa de aplicativo executado no ambiente z/OS
-
Podem usar a segurança RACF para controlar o acesso a recursos não DB2
-
Podem reutilizar lógica de negócios existente chamando os aplicativos existentes como subprogramas
-
São executadas em um ambiente gerenciado pelo z/OS Workload Manager (WLM)
-
Podem aplicar mudanças a UDFs externas usando as interfaces DB2 para z/OS e WLM sem impactar a disponibilidade do serviço
-
Exigem autoridade DB2 EXECUTE para serem mantidas pelo cliente UDF
Em contraste com os procedimentos armazenados, as UDFs externas de DB2 para z/OS fornecem integração com operações SQL DML. Por exemplo:
- As UDFs externas podem ser invocadas a partir de operações SQL DML executadas por ferramentas como DB2I SPUFI, DSNTEP2, DSNTIAD, DSNTIAUL, carga de cursor DB2 para z/OS CROSSLOADER e pelo utilitário DB2 LUW EXPORT.
- Para o preenchimento de tabela, uma UDF de tabela externa pode ser referenciada em uma expressão de tabela de seleção completa ou comum integrada em uma operação de inserção SQL DML.
- Uma UDF de tabela não exige uma tabela DB2 para construir a tabela de resultados. A tabela de resultados é gerenciada internamente pelo espaço de endereço DBM1 do DB2 para z/OS.
- Os elementos da linguagem SQL como expressões, predicados, funções e cláusulas de subseleção (WHERE, GROUP BY, HAVING, ORDER BY, FETCH FIRST), podem ser aplicados à tabela de resultados retornada pelas funções de tabela definidas pelo usuário.
- As funções integradas do DB2 para z/OS e as user-defined functions podem ser aplicadas aos resultados retornados por UDFs externas, e vice-versa.
 |
Lendo arquivos por meio de UDF externa (UDF ReadFile)
Quantias significativas de informações não estruturadas são armazenadas em arquivos e conjuntos de dados z/OS que estão indisponíveis para processamento SQL DML. É possível fornecer integração SQL DML desses arquivos e conjuntos de dados z/OS carregando-os em tabelas DB2 ou fornecendo acesso a arquivo ou conjunto de dados a partir do SQL por meio de UDFs externas. Com a última opção, evita-se o gasto adicional de criar e carregar tabelas adicionais DB2, o que talvez ajude a poupar tempo e recursos, especialmente se for desejável executar análise ad hoc das informações armazenadas apenas em arquivos ou conjuntos de dados e ainda não disponíveis em tabelas DB2. Com arquivos e conjuntos de dados integrados com o SQL DML por meio de UDFs, pode-se facilmente aplicar a funcionalidade do SQL a informações armazenadas em conjuntos de dados z/OS e arquivos USS. Ao longo deste artigo, o termo UDF ReadFile se refere a uma UDF externa que lê um arquivo USS ou um conjunto de dados z/OS. A UDF ReadFile fornece dois modos de retornar o conteúdo do arquivo por UDF disponibilizando-o depois para operações SQL:
- O valor escalar — da UDF escalar externa usada neste artigo retorna um valor escalar CLOB(1M).
- Tabela de resultados — o arquivo a ser lido pela UDF tem uma estrutura de registro conhecida e ela será mapeada pela UDF ReadFile em uma tabela de resultados. A UDF de tabela ReadFile usada neste artigo retorna uma tabela de resultados que contém uma linha de tabela de resultados para cada registro de arquivo. Cada linha de tabela de resultados tem uma coluna VARCHAR (32600) que contém um registro de arquivo. A tabela UDF não faz nenhum mapeamento de campos de registro nas colunas da tabela de resultados. O mapeamento é executado fora da UDF com a mesma instrução SQL. A UDF de tabela externa nesse sentido fornece uma interface genérica para ler registros de arquivo a partir de SQL. Isso significa que é possível usar a UDF de tabela externa para acessar de forma sequencial os registros de arquivo de fontes diferentes, como arquivos QSAM, VSAM e USS, e depois executar mapeamento individual de campo de registro para coluna via SQL.
 |
UDF escalar de ReadFile
Esse cenário trata de uma situação em que você deseja executar uma análise ad hoc em dados XML armazenados em um arquivo (o termo arquivo refere-se a conjuntos de dados z/OS ou a arquivos USS). O arquivo que se deseja analisar é ilustrado na Listagem 1.
Listagem 1. Arquivo XML de UDF escalar ReadFile
<zNTC>
<member>
<fstName>Eric</fstName><name>Cichiello</name><Area>Manager</Area>
</member>
<member>
<fstName>Cedrine</fstName><name>Madera</name><Area>BI Specialist</Area>
</member>
<member>
<fstName>Michael</fstName><name>Schapira</name><Area>Cognos System z</Area>
</member>
<member>
<fstName>Josef</fstName><name>Klitsch</name><Area>DB2 for z/OS</Area>
</member>
</zNTC>
|
Aplique pureXML ao conteúdo do arquivo
Para esse cenário, execute a análise usando pureXML de DB2 para z/OS. Isso exige que o documento XML esteja acessível como valor escalar na lista de seleção da cláusula de uma instrução SQL. A consulta pureXML e seu resultado são mostrados na Figura 1. O cenário usa uma expressão de tabela comum (CTE) de DB2 para z/OS a fim de invocar a UDF escalar ReadFile a partir do SQL. A CTE usa pureXML para mapear elementos XML para colunas de tabela de resultados de DB2 para z/OS.
Figura 1. Visão geral do cenário de UDF escalar ReadFile 
Ambiente de execução da UDF escalar ReadFile
O ambiente de execução da UDF ReadFile envolve o cliente DB2 com sua consulta SQL, o DBM1 de DB2 para z/OS e espaços de endereço DDF, o WLMENV ambiente de aplicativo WLM, o programa externo UDF ReadFile, o ambiente de tempo de execução z/OS XL C/C++ e o arquivo externo que armazena o documento XML que será analisado.
É necessário um ambiente de aplicativo WLM (WLM APPLENV) para planejamento e execução de programas de UDF externa. A WLM APPLENV normalmente é criada em uma instalação DB2 como parte do procedimento de verificação de instalação (IVP) da DB2 para z/OS. Por exemplo, a tarefa IVP DSNTEJ2U prepara e executa as amostras de UDFs C/C++. Após a conclusão bem-sucedida da IVP, um WLM APPLENV com o nome de WLMENV existe no seu ambiente DB2 para z/OS. Pode-se usar esse WLM APPLENV para executar as UDFs externas que são usadas neste artigo. Para obter mais informações sobre configuração de WLM para UDFs externas, veja o "Capítulo 4, Configurando e gerenciando o Workload Manager" do Redbook SG24-7604, Procedimentos Armazenados do DB2 9 para z/OS: O CALL e Mais, cujo link encontra-se na seção Recursos.
A Figura 2 ilustra o fluxo de processamento cronológico dos componentes de ambiente de execução UDF externo.
Figura 2. Ambiente de execução do cenário de UDF escalar ReadFile 
- Um cliente DB2 para z/OS local ou remoto emite uma consulta SQL que invoca a UDF ReadFile fazendo referência à UDF na lista de seleção da cláusula SELECT. Para conexões remotas de IBM Data Server Client, o DB2 executa o seguinte processamento adicional:
- O IBM Data Server Client se conecta ao DDF do DB2 para z/OS (facilidade de dados distribuídos DB2 para z/OS) por meio de TCP/IP e DRDA. O espaço de endereço de DDF do DB2 para z/OS implementa a interface TCP/IP – DRDA no DB2 para z/OS.
- O DDF do DB2 para z/OS passa a solicitação SQL para processamento SQL para o espaço de endereço DBM1 do DB2 para z/OS (gerenciador do banco de dados DB2 para z/OS). O enclave criado e usado pelo espaço de endereço DDF para processamento da solicitação SQL é executado em uma classe de serviço WLM que corresponde à classificação de serviço especificada na política do WLM.
- O espaço de endereço DBM1 do DB2 para z/OS determina que ambiente de aplicativo WLM usar para planejar o programa UDF ReadFile obtendo o nome WLM APPLENV a partir do catálogo e diretório DB2. O nome WLM APPLENV nesse cenário é WLMENV.
- O espaço de endereço DBM1 do DB2 para z/OS cria uma interface com o WLM para executar o programa UDF no ambiente de aplicativo WLMENV WLM.
- A política do WLM contém os atributos do ambiente de aplicativo WLMENV, como parâmetros de invocação e o nome do procedimento JCL que deve ser usado pelo WLM para criação de espaço de endereço. Para a UDF ReadFile, o nome do procedimento JCL é WLMENV.
- O procedimento WLMENV JCL faz referência à biblioteca de módulo de carregamento DB2.DBLN.RUNLIB.LOAD na instrução DD da biblioteca STEPLIB. Não é necessário definir uma instrução JCL DD no procedimento WLMENV JCL para o conjunto de dados JOSEF.XML visto que o programa UDF externo usa o ambiente de tempo de execução z/OS XL C/C++. O ambiente de tempo de execução z/OS XL C/C++ executa de forma transparente a alocação de conjunto de dados dinâmico durante a abertura do conjunto de dados e a desalocação do conjunto de dados durante o processamento do fechamento do conjunto de dados.
- A biblioteca DB2.DBLN.RUNLIB.LOAD contém a UDF ReadFile executável que é carregada pelo z/OS antes da execução do programa UDF.
- O programa UDF ReadFile recebe o controle. Ele usa as funções z/OS XL C/C++ fopen, fread e fclose para abrir, ler e fechar o arquivo JOSEF.XML. Daí, retorna o conteúdo do arquivo JOSEF.XML como valor escalar para o espaço de endereço DBM1 do DB2 para z/OS.
- O espaço de endereço DBM1 do DB2 para z/OS usa o valor escalar retornado pela UDF ReadFile para continuar com seu processamento SQL e retorna o resultado do SQL para o aplicativo cliente DB2.
Criando user-defined functions
As UDFs ReadFile externas descritas neste artigo foram escritas em C. Para criar módulos de carregamento UDF, é preciso compilar os arquivos de origem em C e ligar/editar os módulos de carregamento com a biblioteca de carregamento usada pelo ambiente de aplicativos ReadFile WLM. Não são necessárias ligações com o pacote DB2 porque essas UDFs não contêm operações SQL. Pode-se usar o procedimento JCL chamado DSNHC, fornecido pelo DB2, para criar as UDFs ReadFile. Em uma etapa de tarefa subsequente, usaremos o programa DB2 IVP chamado DSN8ED6 para atualizar o ambiente de aplicativos WLMENV. Isso é necessário para refletir o nível atualizado do módulo de carregamento da UDF ReadFile no ambiente de aplicativos WLM. Um exemplo de JCL é mostrado na Listagem 2.
Listagem 2. Amostra JCL de compilação e ligação/edição UDF
//PH02US03 EXEC DSNHC,MEM=READFLES,COND=(4,LT),
// PARM.PC=(HOSTC,CCSID(1047),MARGINS(1,72),STDSQL(NO)
// SOURCE,XREF),
// PARM.C=SOURCE RENT XREF MARGINS(1,72),
// PARM.LKED=MAP,RENT,REUS,AMODE=31,RMODE=ANY
//PC.DBRMLIB DD DISP=SHR,DSN=JOSEF.DBRMLIB.DATA(READFLES)
//PC.SYSLIB DD DISP=SHR,DSN=JOSEF.SOURCE.DATA
//PC.SYSIN DD DISP=SHR,DSN=JOSEF.SOURCE.DATA(READFLES)
//LKED.SYSLMOD DD DISP=SHR,DSN=DB2.DBLN.RUNLIB.LOAD(READFLES)
//LKED.SYSIN DD *
INCLUDE SYSLIB(DSNRLI)
NAME READFLES(R)
//* ----------------------------------------------------
//* Refresh WLMENV WLM APPLENV
//* Parameters: WLMENV --> WLM APPLENV to be refreshed
//* DBLN --> DB2 subsystem ID
//* DB2GRP --> RACF Group to use for refresh
//* ----------------------------------------------------
//WLMREFR EXEC PGM=IKJEFT01,DYNAMNBR=20,COND=(4,LT)
//SYSTSPRT DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//SYSUDUMP DD SYSOUT=*
//SYSTSIN DD *
DSN SYSTEM(DBLN)
RUN PROGRAM(DSN8ED6) PLAN(DSN8ED6) -
LIB(DSN910.RUNLIB.LOAD) -
PARMS(WLMENV DBLN DB2GRP)
END
//
|
Para obter mais informações sobre a preparação de UDFs C/C++ externas e uso da amostra de programa DB2 chamada DSN8ED6 para atualizar os ambientes de aplicativos UDF WLM, consulte o Guia de Instalação do DB2 9 para z/OS, cujo link se encontra na seção Recursos. Definindo a UDF escalar ReadFile para DB2 para z/OS
A UDF escalar ReadFile retorna o conteúdo inteiro do arquivo como um único valor CLOB. O programa UDF lê e armazena o arquivo inteiro em um valor LOB, que é então retornado ao espaço de endereço DBM1 do DB2 para z/OS. A entrada para essa função é um nome do arquivo que adere às regras de nomenclatura de arquivo do z/OS XL C/C++. Portanto, um nome do conjunto de dados z/OS é incluído em aspas simples e precedido por // (por exemplo, //'JOSEF.XML'). Um nome de arquivo USS é um nome de arquivo absoluto (por exemplo, /tmp/filename.txt). Para obter mais detalhes sobre as regras de nomenclatura de arquivo do z/OS XL C/C++, consulte uma das seções “Abrindo Arquivos” do Guia de Programação de z/OS XL C/C++, cujo link se encontra na seção Recursos. É possível usar a instrução SQL DDL mostrada na Listagem 3 para criar a UDF escalar ReadFile no DB2 para z/OS.
Listagem 3. SQL DDL da UDF escalar ReadFile
CREATE FUNCTION C.READFILESCALAR (DSN VARCHAR(255)) /*1*/
RETURNS CLOB(1M) /*2*/
SPECIFIC “0001 READFILE_SCALAR” /*3*/
LANGUAGE C /*4*/
DETERMINISTIC /*5*/
NO SQL /*6*/
EXTERNAL NAME READFLES /*7*/
PARAMETER STYLE DB2SQL
RETURNS NULL ON NULL INPUT
NO EXTERNAL ACTION
NO SCRATCHPAD
NO COLLID 6
ASUTIME LIMIT 5 /*8*/
STAY RESIDENT YES /*9*/
PROGRAM TYPE SUB /*10*/
WLM ENVIRONMENT WLMENV /*11*/
SECURITY USER /*12*/
DBINFO
DISALLOW PARALLEL
|
Os atributos da UDF externa usados na instrução SQL DDL mostrada na Listagem 3 são explicados abaixo: - O parâmetro de entrada contém um nome de arquivo que adere às regras de nomenclatura de arquivos do ambiente de tempo de execução z/OS XL C/C++.
- A função retorna um valor CLOB que tem, no máximo, 1 megabyte de comprimento.
- A parte numérica do nome específico UDF é usada pelo programa UDF como parâmetro de tempo de execução para determinar o tamanho máximo da área de retorno. No exemplo DDL acima, o valor inicial de
0001 indica ao programa UDF que a área de retorno pode ter até 1 megabyte de tamanho. Esse valor precisa corresponder às informações de comprimento fornecidas na expressão RETURN.
- A função externa é escrita em C/C++.
- As invocações de função repetitivas com o mesmo parâmetro de entrada retornam o mesmo valor escalar.
- A função externa não contém SQL e, portanto, não tem ID de coleta de pacote DB2.
- O nome do módulo de carregamento da UDF externa é READFLES.
- A UDF escalar ReadFile tem um limite ASUTIME de 5 service units (SUs). Essa é a quantia total do tempo de processador que a UDF externa pode usar. Se o limite for ultrapassado, o DB2 para z/OS envia mensagens DSNX908I para o console e encerra a UDF.
- O programa da UDF externa deve continuar na memória após ser carregado.
- Os programas PROGRAM TYPE SUB UDF C não têm uma função principal. O Ambiente de Linguagem (LE) z/OS não realiza a reinicialização do programa. O programa UDF tem de cuidar da inicialização de variáveis.
- O nome do ambiente de aplicativos WLM onde a UDF externa deve ser executada é WLMENV.
- O DB2 usa a segurança externa (RACF) z/OS para controlar o acesso a recursos não DB2. Para o RACF DATASET da UDF ReadFile, o controle de acesso é exercido pelo usuário que foi autenticado no DB2 para z/OS.
O código C que implementa a função escalar do ReadFile é mostrado na Listagem 4.
Listagem 4. Código C UDF escalar ReadFile
#pragma linkage(READFLES,fetchable)
#include <stdio.h>
#include <stdarg.h>
#include <sqludf.h>
void SQL_API_FN READFLES(
SQLUDF_VARCHAR *fileName, /*1*/
SQLUDF_CLOB *fileData,
SQLUDF_NULLIND *fileName_ind,
SQLUDF_NULLIND *fileData_ind,
SQLUDF_TRAIL_ARGS_ALL)
{
int rc = 0;long fileSize = 0; long maxSize = 0;
size_t readCnt = 0; FILE *f = NULL;
f = fopen(fileName,”rb,byteseek”); /*2*/
if (!f) {
strcpy(SQLUDF_MSGTX, “Could not open file “);
strncat(SQLUDF_MSGTX, fileName,
SQLUDF_MSGTEXT_LEN - strlen(SQLUDF_MSGTX)-1);
strncpy(SQLUDF_STATE, “38100”, SQLUDF_SQLSTATE_LEN);
return;
}
rc = fseek(f, 0, SEEK_END); /*3*/
if (rc) {
sprintf(SQLUDF_MSGTX, “fseek() failure rc = %d”, rc);
strncpy(SQLUDF_STATE, “38101”, SQLUDF_SQLSTATE_LEN);
return;
}
fileSize = ftell(f); /*4*/
maxSize = atoi(SQLUDF_FSPEC)*1024000 ;
if (fileSize > maxSize ) {
sprintf(SQLUDF_MSGTX,
“File too large,max = %d,size=%d”, maxSize,fileSize);
strncpy(SQLUDF_STATE, “38102”, SQLUDF_SQLSTATE_LEN);
fclose(f);
return;
}
rc = fseek(f, 0, 0); /*5*/
if (rc) {
sprintf(SQLUDF_MSGTX, “fseek() failed with rc = %d”, rc);
strncpy(SQLUDF_STATE, “38103”, SQLUDF_SQLSTATE_LEN);
fclose(f);
return;
}
readCnt = fread(fileData->data, 1, fileSize, f); /*6*/
if (readCnt != fileSize) {
sprintf(SQLUDF_MSGTX, “Could not read entire file “
“(%d vs %d)”, readCnt, fileSize);
strncpy(SQLUDF_STATE, “38104”, SQLUDF_SQLSTATE_LEN);
*fileData_ind = -1;
}
else {
fileData->length = readCnt;
*fileData_ind = 0;
}
fclose(f); /*7*/
}
|
O programa da UDF externa mostrado na Listagem 4 executa as seguintes etapas de processamento: - Recebe o nome do arquivo na notação de nome do arquivo z/OS XL C/C++.
- Usa o nome do arquivo para abri-lo. O ambiente de tempo de execução z/OS XL C/C++ gerencia implicitamente a alocação de conjunto de dados.
- Posiciona o ponteiro do registro atual no fim do arquivo.
- Determina o tamanho do arquivo para assegurar que nenhum dado saia truncado. A parte numérica do nome específico da função é usada para determinar o tamanho máximo que é suportado pelo parâmetro de retorno.
- Posiciona o ponteiro do registro atual no início do arquivo.
- Lê o arquivo inteiro na coluna de retorno CLOB e fornece a informação de comprimento do CLOB.
- Fecha o arquivo. O ambiente de tempo de execução z/OS XL C/C++ gerencia implicitamente a desalocação de conjunto de dados.
É possível instalar o programa UDF no DB2 para z/OS executando o procedimento JCL que é explicado na seção Criando user-defined functions deste artigo.
Outros cenários de uso
O cenário descrito nesta seção aplicou pureXML ao conteúdo do arquivo que foi retornado como valor escalar pela UDF ReadFile. A pureXML é apenas das várias opções de que você dispõe. Por exemplo, pode-se usar também qualquer uma entre o grande conjunto de funções integradas fornecidas pelo DB2 para z/OS e suas próprias UDFs escalares existentes em suas análises ad hoc.
Além de análise ad hoc, é possível usar a UDF escalar ReadFile para inserir conteúdo de arquivo de dentro de instruções de inserção SQL preparadas dinamicamente direto nas colunas LOB ou XML. O cenário mostrado na Listagem 5 insere diretamente o conteúdo do arquivo ilustrado na Listagem 1 em uma coluna da tabela XML e subsequentemente usa pureXML para reler o documento para fins de validação.
Listagem 5. UDF escalar ReadFile para inserção de documento
CREATE TABLE RF.NTCTAB (XMLDOC XML);
---------+---------+---------+---------+---------+---------+--
DSNE616I STATEMENT EXECUTION WAS SUCCESSFUL, SQLCODE IS 0
---------+---------+---------+---------+---------+---------+--
Insert into rf.ntctab
values ( c.readFileScalar(//JOSEF.XML));
---------+---------+---------+---------+---------+---------+--
DSNE615I NUMBER OF ROWS AFFECTED IS 1
DSNE616I STATEMENT EXECUTION WAS SUCCESSFUL, SQLCODE IS 0
---------+---------+---------+---------+---------+---------+--
SELECT zNTCR.* FROM RF.NTCTAB,
XMLTABLE ($d/zNTC/member passing XMLDOC as ”d”
COLUMNS
”1stName” Varchar(15) PATH fstName/text()
,”Name” Varchar(15) PATH Name/text()
,”Title” Varchar(15) PATH Area/text()
) AS zNTCR ;
---------+---------+---------+---------+---------+---------+----
1stName Name Title
---------+---------+---------+---------+---------+---------+----
Eric Cichiello Manager
Cedrine Madera BI Specialist
Michael Schapira Cognos System z
Josef Klitsch DB2 for z/OS
DSNE610I NUMBER OF ROWS DISPLAYED IS 4
|
Usar a técnica de inserção mostrada na Listagem 5 pode ser útil porque o suporte para variável de referência de arquivo para XML e as colunas LOB estão indisponíveis nas ferramentas DB2 para z/OS, como DB2I SPUFI, DSNTEP2, DSNTIAD e DSNTIAUL. Consideração de segurança RACF
A UDF ReadFile acessa conjuntos de dados e arquivos protegidos por RACF. Com SECURITY USER ativada para a UDF ReadFile, usamos o RACF para controlar o acesso a arquivos e conjuntos de dados por meio do ID de autorização primário do invocador da UDF. A UDF ReadFile recebe uma falha de acesso RACF se tenta abrir um arquivo para o qual o invocador UDF não tem privilégio de acesso apropriado. Uma mensagem RACF correspondente, detalhando a violação da segurança, é enviada para o z/OS SYSLOG (veja a Listagem 6). Nessa situação, a UDF ReadFile não é capaz de abrir o arquivo e retorna SQLSTATE 38100 para o DB2 para z/OS, que, por sua vez, fornece SQLCODE -443 ao aplicativo cliente DB2, indicando falha de processamento (veja a Listagem 7).
Listagem 6. Mensagem de violação de segurança RACF da UDF ReadFile
------ Data Set ---------------------------------
ICH408I USER(SYSADM ) GROUP(ADMIN ) NAME( DB2 )
JOSEF.XML CL(DATASET ) VOL(DMTU03)
INSUFFICIENT ACCESS AUTHORITY
FROM JOSEF.** (G)
ACCESS INTENT(READ ) ACCESS ALLOWED(NONE )
------ Unix System Services file ---------------
ICH408I USER(SYSADM ) GROUP(ADMIN ) NAME( DB2 )
/u/josef/zntc_bi_team.xml
CL(DIRSRCH ) FID(01C4D4E3E4F0F200042F000000000003)
INSUFFICIENT AUTHORITY TO OPEN
ACCESS INTENT(--X) ACCESS ALLOWED(OTHER ---)
EFFECTIVE UID(0000000607) EFFECTIVE GID(0000000011)
|
Listagem 7. Violação de segurança RACF SQLCODE -443
SQL0443N Routine “READFILESCALAR” (specific name “0001 READFILE_SCALAR”) has returned an
error SQLSTATE with diagnostic text “Could not open file //JOSEF.XML”. SQLSTATE=38100
|
UDF de tabela ReadFile
Este cenário trata de uma situação em que queremos executar análise ad hoc em dados armazenados em registros de arquivo que têm uma estrutura de registro conhecida. Durante a análise, usamos funções integradas SQL existentes ou UDFs para mapear informações de campo de registro de arquivo nas colunas da tabela de resultados. Os arquivos que desejamos analisar têm duas estruturas de registro diferentes:
- Fixa — cada campo pode ser encontrado em locais de registro fixos
- Delimitada — os campos são separados por delimitadores e sua localização dentro de cada registro varia
Mapear estruturas de registro de arquivo fixo em colunas da tabela de resultados
Esse cenário usa a UDF ReadFile junto com funções integradas SQL para mapear campos de registro de arquivo em colunas da tabela de resultados. A Listagem 8 mostra os registros de arquivo que são usados no cenário.
Listagem 8. Conteúdo de arquivo de estrutura de registro fixo da UDF
----+----1----+----2----+----3----+----4----+----5----+----6
Eric Cicchiello zNTC Manager
Cedrine Madera zNTC BI specialist
Michael Schapira zNTC Cognos System z
Josef Klitsch zNTC DB2 for z/OS
|
A estrutura desses registros de arquivo é ilustrada na Tabela 1.
Tabela 1. Estrutura de registro fixo da tabela ReadFile
|
Início da Coluna
|
Fim da Coluna
|
Descrição
|
|---|
| 01 | 19 | Primeiro nome | | 20 | 39 | Nome | | 40 | 44 | Departamento | | 45 | 60 | Cargo |
Para a parte de análise nesse cenário, use as funções integradas do DB2 para z/OS para desencadear os registros de arquivo. A consulta que você executar e seu resultado são mostrados na Figura 3. No cenário ilustrado abaixo, use uma expressão de tabela comum (CTE) de DB2 para z/OS a fim de invocar a UDF de tabela ReadFile a partir do SQL. Dentro da mesma CTE, use as funções integradas DB2 SUBSTR, CHAR e STRIP para mapear a estrutura das linhas da tabela de resultados da UDF nas colunas da tabela de resultados. Figura 3. Visão geral do cenário da UDF de tabela ReadFile  A UDF de tabela ReadFile retorna os registros de arquivo em uma linha de tabela de resultados de comprimento variável para cada registro de arquivo. Talvez tenha notado que o programa UDF em si não executa mapeamento de coluna. Em vez disso, ele lê e retorna registros de arquivos como estão na consulta SQL. O mapeamento da estrutura de campo de registro para coluna é executado pelas funções integradas do DB2 para z/OS fora da UDF de tabela ReadFile e dentro da mesma expressão de tabela comum (CTE) de DB2 para z/OS. A UDF de tabela ReadFile fornece uma interface genérica para ler os registros de arquivo a partir do SQL. Portanto, é possível usar a UDF de tabela ReadFile para ler registros de arquivo que vêm de várias fontes, incluindo arquivos QSAM, VSAM e USS. Ambiente de execução da UDF de tabela ReadFile
A UDF de tabela ReadFile usa a mesma infraestrutura da sua correspondente escalar. Portanto, as informações fornecidas em Ambiente de execução da UDF escalar ReadFile também se aplicam, com as seguintes exceções:
- A UDF de tabela é invocada via referência a função de tabela que pode ser especificada na cláusula FROM da instrução de seleção SQL.
- Em vez de valor escalar, o DB2 para z/OS retorna uma tabela de resultados para o invocador da UDF.
- O DB2 para z/OS e o programa UDF interagem entre si usando tipos de chamada de função. Por exemplo, o DB2 para z/OS invoca o programa da UDF de tabela ReadFile uma vez para os tipos de chamada FIRST, OPEN, CLOSE e FINAL, e invoca a UDF de tabela externa repetidas vezes para o tipo de chamada FETCH até que o programa UDF retorne SQLSTATE 02000, indicando o fim do processamento da tabela de resultados. O programa da UDF ReadFile converte então esses tipos de chamada em invocações de API fopen, fread e fclose.
- A UDF de tabela ReadFile retorna SQLSTATE 02000 depois que a operação de leitura de arquivo chegou à condição de fim do arquivo (EOF).
Figura 4. Ambiente de execução da UDF de tabela ReadFile  Definindo a UDF de tabela ReadFile para DB2 para z/OS
A entrada para a função de tabela ReadFile é um nome do arquivo com o mesmo formato do parâmetro de entrada da UDF escalar ReadFile. As informações fornecidas em Definindo a UDF escalar ReadFile para DB2 para z/OS também se aplicam a esse cenário.
É possível usar a instrução SQL DDL mostrada na Listagem 9 para criar a UDF de tabela ReadFile no DB2 para z/OS.
Listagem 9. DDL da UDF de tabela ReadFile
CREATE FUNCTION C.READFILE(DSN VARCHAR(255))
/*1*/
RETURNS TABLE (FILERECORD VARCHAR(32600 ))
/*2*/
SPECIFIC READFILE PARAMETER VARCHAR STRUCTURE
/*3*/ LANGUAGE C /*4*/
DETERMINISTIC
/*5*/
NO SQL
/*6*/
EXTERNAL NAME READFILE
/*7*/
PARAMETER STYLE DB2SQL RETURNS NULL ON NULL INPUT NO EXTERNAL ACTION SCRATCHPAD
/*8*/
FINAL CALL NO COLLID 6 ASUTIME LIMIT 100
/*9*/
STAY RESIDENT YES
/*10*/
PROGRAM TYPE SUB
/*11*/
WLM ENVIRONMENT WLMENV
/*12*/
SECURITY USER
/*13*/
DBINFO DISALLOW PARALLEL
|
Os atributos da UDF externa usados na instrução SQL DDL mostrada na Listagem 9 são explicados abaixo: - O parâmetro de entrada contém um nome de arquivo que adere às regras de nomenclatura de arquivos do ambiente de tempo de execução z/OS XL C/C++.
- A UDF retorna uma tabela de resultados. O comprimento máximo de uma linha da tabela de resultados é de 32600 bytes. Esse valor é derivado do comprimento total máximo das colunas de uma operação de consulta que exija funções de coluna de classificação e avaliação (MULTIPLE DISTINCT e GROUP BY).
- PARAMETER VARCHAR STRUCTURE é exigido para valores '00' hexadecimais retornados nas colunas da tabela de resultados VARCHAR. Esse é um requisito válido porque um registro de arquivo pode conter um número inteiro ou valores de campo decimal compactado armazenados em formato binário interno.
- A função é escrita em C/C++.
- As invocações de função repetitivas com o mesmo parâmetro de entrada retornam o mesmo valor escalar.
- A função externa não contém SQL e, portanto, não tem ID de coleta de pacote DB2.
- O nome do módulo de carregamento do programa UDF é READFILE.
- A UDF usa uma área de rascunho para salvar e passar a referência de ponteiro de arquivo obtida pelo API fopen entre as chamadas UDF.
- A UDF de tabela ReadFile tem um limite ASUTIME de 100 service units (SUs). Essa é a quantia total do tempo de processador que a UDF externa pode usar. Se o limite for ultrapassado, o DB2 para z/OS envia mensagens DSNX908I para o console e encerra a UDF.
- O programa da UDF externa deve continuar no armazenamento virtual após ser carregado.
- Os programas PROGRAM TYPE SUB UDF C não têm uma função principal. O Ambiente de Linguagem (LE) z/OS não realiza a reinicialização do programa. O programa UDF tem de cuidar da inicialização de variáveis. Essa configuração é necessária na UDF de tabela ReadFile a fim de ter controle total sobre o fechamento do arquivo e a desalocação. PROGRAM TYPE MAIN faz LE fechar o arquivo entre as invocações do programa UDF.
- O nome do ambiente de aplicativos WLM onde a UDF externa deve ser executada é WLMENV.
- O DB2 usa a segurança externa (RACF) z/OS para controlar o acesso a recursos não DB2. O RACF executa o controle de acesso DATASET para o usuário que foi autenticado no DB2 para z/OS. As informações da seção Consideração de segurança RACF também se aplicam aqui.
O código C que implementa a função de tabela do ReadFile é mostrado na Listagem 10.
Listagem 10. Código C da UDF de tabela ReadFile
#pragma linkage(READFILE,fetchable)
#include <stdio.h>
#include <stdarg.h>
#include <sqludf.h>
struct SCRATCHDATA { FILE *p;};
void SQL_API_FN READFILE(SQLUDF_VARCHAR_FBD *fileName, /*1*/
SQLUDF_VARCHAR_FBD *clob32600,
SQLUDF_NULLIND *fileNameInd,
SQLUDF_NULLIND *clob32600IND,
SQLUDF_TRAIL_ARGS_ALL)
{ long i = 0; int num = 0; char errMsg[0100]; char fileNameTmp[0255];
struct SCRATCHDATA *sp; sp = (struct SCRATCHDATA *) SQLUDF_SCRAT->data;
switch (SQLUDF_CALLT)
{ case SQLUDF_TF_FIRST:
if (*fileNameInd == -1)
{strcpy( SQLUDF_STATE, “38700”);
sprintf (errMsg, “file name missing”);
strcpy( SQLUDF_MSGTX, errMsg);
break;}
strncpy(fileNameTmp,fileName->data,fileName->length);
memcpy( fileNameTmp+fileName->length,”\0”,1);
sp->p = fopen(fileNameTmp,”rb,type=record”); /*2*/
if (sp->p == NULL)
{strcpy( SQLUDF_STATE, “38701”);
sprintf (errMsg, “data set cannot be opened”, fileName);
strcpy( SQLUDF_MSGTX, errMsg);
break; }
case SQLUDF_TF_OPEN:
break;
case SQLUDF_TF_FETCH:
num = fread(clob32600->data ,1, 32600, sp->p) ; /*3*/
if (num == 0)
{strcpy( SQLUDF_STATE, “02000”);break; } /*4*/
clob32600->length = num ;
*clob32600IND = 0;
break;
case SQLUDF_TF_CLOSE:
fclose(sp->p); break; /*5*/
case SQLUDF_TF_FINAL:
break;
}
}
|
O programa da UDF externa mostrado na Listagem 10 executa as seguintes etapas de processamento principais: - O DB2 para z/OS trata os valores de parâmetro VARCHAR para programas UDF em linguagem C como sequências encerradas NULL. Para a UDF de tabela ReadFile, esse comportamento é indesejável visto que os registros de arquivo podem conter valores decimais compactados ou números inteiros armazenados em formato binário interno. A UDF de tabela ReadFile é, portanto, definida com o atributo PARAMETER VARCHAR STRUCTURE. Esse atributo faz o DB2 para z/OS tratar parâmetros C-UDF VARCHAR externos como estruturas VARCHAR reais para as quais pequenas informações de comprimento de número inteiro são mantidas pelo DB2 para z/OS para parâmetros VARCHAR de entrada e pelo programa C-UDF para parâmetros VARCHAR de saída. A definição de estrutura SQLUDF_VARCHAR_FBD (para dados de bit) é, portanto, usada por parâmetros VARCHAR.
- Abre o arquivo quando invocado com o tipo de chamada SQLUDF_TF_FIRST. O API fopen abre o arquivo indicado pela variável fileName. O modo fopen "rb,type=record" abre o arquivo em modo binário de leitura para processamento de registro. O modo binário foi escolhido para suprimir as conversões de caracteres. A alocação de conjunto de dados é executada de forma transparente pelo ambiente de tempo de execução z/OS XL C/C++ durante o processamento fopen.
- Leia o próximo registro e forneça a informação de comprimento de VARCHAR quando invocada com o tipo de chamada SQLUDF_TF_FETCH.
- Indica o fim do processamento da tabela de resultados quando não há mais dados a ler.
- Fecha o arquivo quando invocado com o tipo de chamada SQLUDF_TF_CLOSE. A desalocação de conjunto de dados é executada de forma transparente pelo ambiente de tempo de execução z/OS XL C/C++ durante o processamento fclose.
É possível instalar o programa UDF no DB2 para z/OS executando o procedimento JCL que é explicado na seção Criando user-defined functions deste artigo.
Estrutura de registro de arquivo delimitado por mapa para colunas da tabela de resultados
Esse cenário mostra como usar a UDF de tabela ReadFile com o COBOL RF.GETCOL UDF para mapear campos de registro de arquivo delimitado por caractere de mapa para colunas da tabela de resultados. Os registros de arquivo que processamos nesse cenário são apresentados na Listagem 11.
Listagem 11. Conteúdo de arquivo de estrutura de registro delimitado por UDF de tabela
Josef!Klitsch!DB2 for z/OS!zNTC
Michael!Schapira!Cognos on System z!zNTC
Cedrine!Madera!BI Specialist!zNTC
Eric!Cicchiello!Manager!zNTC
|
A estrutura do registro de arquivo nesse caso não é fixa. As informações de campo contidas nos registros de arquivo estão em várias localizações no registro e são delimitadas por um único delimitador de caractere — o caractere "!". O desafio nesse cenário é usar o SQL para localizar o ponto de exclamação e extrair a palavra que deve ser mapeada para uma coluna da tabela de resultados. Conseguir isso usando as funções integradas do DB2 para z/OS é bastante complexo. Para reduzir essa complexidade, esse cenário implementa a função RF.GETCOL. A função escalar RF.GETCOL é uma UDF externa escrita em COBOL. O código COBOL é fornecido no arquivo DWSReadFile.zip, cujo link se encontra na seção Downloads. É possível definir a função RF.GETCOL usando o SQL DDL mostrado na Listagem 12.
Listagem 12. UDF DDL escalar RF.getCol
CREATE FUNCTION RF.getCol
(inString VARCHAR(2048),
inDelim VARCHAR(0001),
inWordPos INTEGER )
RETURNS VARCHAR(2048)
EXTERNAL NAME GETCOL
LANGUAGE COBOL
DETERMINISTIC
PARAMETER STYLE DB2SQL
FENCED
RETURNS NULL ON NULL INPUT
NO EXTERNAL ACTION
NO SCRATCHPAD
NO FINAL CALL
ALLOW
DBINFO
NO COLLID
WLM ENVIRONMENT WLMENV3
ASUTIME NO LIMIT
STAY RESIDENT YES
PROGRAM TYPE SUB
SECURITY DB2
STOP AFTER SYSTEM DEFAULT FAILURES
INHERIT SPECIAL REGISTERS
|
O uso da função RF.GETCOL é ilustrado na Listagem 13.
Listagem 13. Amostra de uso da função RF.getCol
select
rf.GETCOL(word1!word2!word3!word4,!,3) from sysibm.sysdummy1;
---------+---------+---------+---------+---------+---------+-----
word3
DSNE610I NUMBER OF ROWS DISPLAYED IS 1
DSNE616I STATEMENT EXECUTION WAS SUCCESSFUL, SQLCODE IS 100
|
O uso da função é simples e direto:
- O parâmetro 1 contém a cadeia de caractere de entrada que contém a palavra a ser extraída.
- O parâmetro 2 contém um delimitador de um byte.
- O parâmetro 3 contém a posição da palavra (por exemplo, se é especificado um valor de "4", a quarta palavra delimitada pelo parâmetro 2 é extraída do parâmetro 1 e retornada em um valor escalar).
Depois de instalar o RF.GETCOL UDF, estamos prontos para executar a consulta mostrada na Figura 5. Nesse cenário, usamos uma expressão de tabela comum (CTE) de DB2 para z/OS para invocar a UDF de tabela ReadFile a partir do SQL. Dentro dessa CTE, é possível usar a UDF escalar RF.GETCOL para mapear a estrutura de registro delimitada das linhas da tabela de resultados retornadas pela UDF de tabela ReadFile para as colunas da tabela de resultados. Figura 5. Visão geral do cenário de estrutura de registro delimitada do ReadFile
 O ambiente de execução nesse cenário é similar ao ilustrado na Figura 4. As informações fornecidas na seção Ambiente de execução da UDF de tabela ReadFile também se aplicam aqui.
Exemplo: Análise do registro de acesso HTTPD
Esse cenário trata de uma situação em que queremos executar análise ad hoc em um registro de acesso HTTPD armazenado no sistema de arquivos USS. O cenário exige que a UDF de tabela ReadFile e a UDF escalar RF.GETCOL estejam implementadas e disponíveis para uso. Veremos que essas duas UDFs são suficientes para executar uma análise mais complexa no arquivo de log de acesso HTTPD. Um trecho do arquivo de log de acesso HTTPD que será analisado está ilustrado na Listagem 14.
Listagem 14. Registro de acesso HTTPD
10.254.1.10 - - [07/Nov/2008:10:39:42 +0100] "GET /images/backgr.gif HTTP/1.1" 200 183099
10.254.1.10 - - [07/Nov/2008:10:39:45 +0100] "GET /favicon.ico HTTP/1.1" 404 281
127.0.0.1 - - [12/Nov/2008:14:56:42 +0100] "POST /cognos8/cgi/cognos.cgi HTTP/1.1" 404 294
10.254.1.10 - - [12/Nov/2008:17:09:31 +0100] "GET /http_srv_styles.css HTTP/1.1" 200 1018
10.254.1.10 - - [12/Nov/2008:17:09:31 +0100] "GET /images/odot.jpg HTTP/1.1" 404 285
|
O layout de registro das entradas de registro acima é conhecido no Servidor HTTP Apache como Formato de Registro Comum (CLF). Para mais detalhes sobre o padrão CLF Apache, use o link para Arquivos de Registro do Servidor HTTP Apache Versão 2.0 na seção de Recursos. Para a análise do registro de acesso HTTP, mapeie os campos de entrada de registro nas colunas da tabela de resultados. Visto que o formato CLF fornece as informações de campo em vários locais, use o RF.GETCOL UDF para extração de campo. Os campos que desejamos extrair, o delimitador de campo de um byte e a posição relativa da palavra do campo de registro dentro das entradas de registro são mostrados na Tabela 2.
Tabela 2. Campos e delimitadores de registro de acesso HTTPD
|
Nome de Campo
|
Delimitador
|
Posição da palavra
|
Comentário
|
|---|
| Servidor | em branco | 1 | Endereço IP/ Nome de Domínio | | Usuário | em branco | 3 | ID do Usuário, pode conter - | | Data/Hora | ] | 2 | Data, hora, compensação de hora | | Status | Em branco | 9 | Código de status | | Tamanho | Em branco | 10 | Tamanho do objeto retornado | | Solicitação | X'7f' --> “ | 2 | Método, recurso, protocolo |
O cenário ilustrado na Figura 6 usa uma expressão de tabela comum (CTE) de DB2 para z/OS para invocar a UDF de tabela ReadFile a partir do SQL. Dentro dessa CTE, a UDF escalar RF.GETCOL é usada para localizar e mapear os campos de entrada de registro em colunas da tabela de resultados. Para acessar as informações do campo de entrada de registro, é invocada a RF.GETCOL UDF e são passados os delimitadores e as posições relativas das palavras como parâmetros de entrada.
Figura 6. Visão geral do cenário de registro de acesso HTTPD da UDF de tabela ReadFile 
Procedimento nativo SQL para análise de consulta múltipla
O cenário mostrado na Figura 6 ilustra apenas o recurso de geração de relatórios de base. Visto que é possível usar a UDF de tabela ReadFile para ter o arquivo de log de acesso integrado com o processamento SQL, podemos estender a análise por qualquer relatório que pode ser criado usando SQL. Por exemplo, podemos determinar:
- A hora do dia ou o dia da semana em que o servidor da Web esteve mais ativo
- O endereço IP que emitiu mais solicitações para o servidor da Web
- A URL mais popular no servidor da Web
- Número de acessos em determinado período por URL ou endereço IP
- Número total de bytes enviados para navegadores remotos
O cenário de registro de acesso HTTPD ilustrado na Figura 7 invoca o procedimento nativo HTTPD_ACCESS_LOG SQL para criar uma tabela temporária global declarada (DGTT), invoca a UDF de tabela ReadFile de dentro de uma instrução SQL INSERT para o preenchimento DGTT e usa os cursores SQL para retornar as seguintes informações para o aplicativo cliente DB2: - As três principais entradas de registro com o maior número de bytes enviados ao cliente Web
- Os três principais endereços IP com o maior número de bytes enviados ao cliente Web
- Os três principais pedidos de HTTP com o maior número de bytes enviados ao cliente Web
Figura 7. Cenário de procedimento nativo HTTPDLOG SQL  O DDL para definir o procedimento nativo HTTPD_Access_Log SQL é fornecido no arquivo DWSReadFile.zip, cujo link se encontra na seção Downloads. Procedimento SQL de conjunto de resultados múltiplo como Data Web Service
Para a próxima etapa, vamos expor o procedimento HTTP_ACCESS_LOG SQL como serviço da Web usando a metodologia descrita na Parte 1 desta série de artigos. Use o Data Studio Developer para executar as tarefas de implementação descritas abaixo: - Configurar e estabelecer uma conexão com o banco de dados.
- Criar o projeto de desenvolvimento de dados UDFReadFile.
- Criar o projeto Web Services HTTPD_Access_Log.
- Arrastar e soltar o procedimento HTTPD_Access_Log SQL no projeto Web Services.
- Criar um arquivo Web Application Archive (arquivo WAR).
- Instalar o arquivo WAR no seu ambiente do servidor de aplicativo J2EE.
Após a implementação bem-sucedida do arquivo WAR HTTPD_Access_Log, é possível usar um cliente de serviço da Web à sua escolha para invocar o serviço Data Web. O documento de resposta XML mostrado na Figura 8 foi criado usando um pedido HTTP RPC estilo REST emitido por meio do utilitário curl. O arquivo access_log usado no pedido HTTP RPC estilo REST é fornecido no arquivo DWSReadFile.zip, cujo link se encontra na seção Downloads. Figura 8. Resposta HTTP REST RPC XML  Relatórios baseados em HTML com transformação IBM DWS e XSLT
A seguir, use a folha de estilo XSLT mostrada na Listagem 15 para transformar a resposta XML ilustrada na Figura 8 em HTML. Isso transforma o serviço da Web HTTPD_Access_Log em um aplicativo de navegador baseado em HTML. A folha de estilo XSLT gera três tags de tabela HTML, uma para cada conjunto de resultados de procedimento armazenado.
Listagem 15. Folha de estilo XSLT do registro de acesso HTTPD
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html" encoding="UTF-8" media-type="text/html"/>
<xsl:template match="/*">
<html>
<head><title>HTTPD Access Log Analysis</title></head>
<body>
<h1>HTTPD Access Log Analysis</h1>
<h2>Top 3 Log Entries by Bytes sent</h2>
<table border="1"> <tr bgcolor="#9acd32">
<td>IPAddr</td><td>Userid</td><td>Date-Time</td>
<td>Response Code</td><td>Byte sent</td><td>Request</td>
</tr>
<xsl:for-each select="rowset/row">
<tr>
<td><xsl:value-of select="IPADDR/text()"/></td>
<td><xsl:value-of select="USERID/text()"/></td>
<td><xsl:value-of select="DATETIME/text()"/></td>
<td><xsl:value-of select="STATUS/text()"/></td>
<td><xsl:value-of select="SIZE"/></td>
<td><xsl:value-of select="REQUEST/text()"/></td>
</tr>
</xsl:for-each>
</table>
<h2>Top 3 Client IP addresses by Bytes sent</h2>
<table border="1"> <tr bgcolor="#9acd32">
<td>Hits</td><td>Byte sent</td><td>Client IP-Address</td>
</tr>
<xsl:for-each select="rowset2/row">
<tr>
<td><xsl:value-of select="HITS"/></td>
<td><xsl:value-of select="TOTSIZE"/></td>
<td><xsl:value-of select="IPADDR/text()"/></td>
</tr>
</xsl:for-each>
</table>
<h2>Top 3 HTTP Requests by Bytes Sent</h2>
<table border="1"> <tr bgcolor="#9acd32">
<td>Hits</td><td>Byte sent</td><td>AVG Byte sent</td><td>Request</td>
</tr>
<xsl:for-each select="rowset3/row">
<tr>
<td><xsl:value-of select="HITS"/></td>
<td><xsl:value-of select="TOTSIZE"/></td>
<td><xsl:value-of select="AVGSIZE"/></td>
<td><xsl:value-of select="REQUEST/text()"/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
|
Para ativar a folha de estilo mostrada na Listagem 15 para transformação de mensagem de saída XSLT, use a metodologia explicada na Parte 1 desta série de artigos. Isso envolve as seguintes tarefas de implementação: - Atribuir a folha de estilo XSLT mostrada na Listagem 15 à operação de serviço da Web HTTPD_ACCESS_LOG para transformação de mensagem de saída.
- Criar e reimplementar o arquivo WAR HTTPD_ACCESS_LOG.
Quando invocamos o serviço da Web HTTPD_Access_Log Web a partir do navegador usando um pedido HTTP RPC estilo REST, vemos a tela mostrada na Figura 9. Figura 9. Relatório HTTPD_Access_Log no Navegador 
AccountInquiry DWS acessando um conjunto de dados VSAM
Esta parte do artigo mostra como usar a UDF de tabela ReadFile para fornecer acesso aleatório a dados VSAM. Para ilustrar, a amostra de cenário bancário apresentada na Parte 1 desta série de artigos foi alterada para armazenar as informações de detalhes da conta em um conjunto de dados VSAM. As informações ListCustomer e AccountSummary continuaram nas tabelas DB2. Portanto, o procedimento armazenado AccountDetail teve ser alterado para invocar a UDF de tabela ReadFile para ler aleatoriamente o conjunto de dados VSAM a partir de SQL e recuperar as informações de detalhes da conta de determinado número de conta. A interface do procedimento armazenado AccountDetail permaneceu inalterada, permitindo que o AccountInquiry DWS seja usado no que se refere ao restante da infraestrutura DWS. Uma visão geral AccountInquiry refletindo a mudança na infraestrutura é fornecida na Figura 10. Figura 10. AccountInquiry DWS com acesso VSAM  Recurso de leitura sequencial de chave VSAM pela UDF de tabela ReadFile
Em um ambiente típico de cliente, provavelmente encontraremos conjuntos de dados VSAM de tamanho maior. Ler tais conjuntos de dados de forma sequencial não é aconselhável por causa do custo associado aos tempos longos de resposta. Esta parte do artigo mostra-lhe como usar um intervalo de chaves para leitura sequencial de chave de dados VSAM pela UDF ReadFile. Além do nome do conjunto de dados, o programa UDF simplesmente recebe dois parâmetros adicionais (chave de início e de fim) e os usa para leitura sequencial de chave. Um trecho do programa de origem ReadFile C é mostrado na Listagem 16 e usado para explicar mudanças adicionais executadas no programa UDF ReadFile. O programa de origem completo em C é fornecido no arquivo DWSReadFile.zip, cujo link se encontra na seção Downloads.
Listagem 16. Recurso de leitura sequencial de chave ReadFileUDF
struct SCRATCHDATA
{
FILE *p;
long vsamkeylen; /*4*/
long vsamRKP ;
};
void SQL_API_FN READFILK(SQLUDF_CHAR *fileName,
SQLUDF_CHAR *VSAMkey, /*1*/
SQLUDF_CHAR *Keyend,
SQLUDF_VARCHAR_FBD *clob32600,
SQLUDF_NULLIND *fileNameInd,
SQLUDF_NULLIND *VSAMkeyInd,
SQLUDF_NULLIND *KeyendInd,
SQLUDF_NULLIND *clob32600IND,
SQLUDF_TRAIL_ARGS_ALL)
{
int num = 0; char errMsg[0100]; char filenameTmp[0100];
fldata_t fileinfo; struct SCRATCHDATA *sp;
sp = (struct SCRATCHDATA *) SQLUDF_SCRAT->data;
switch (SQLUDF_CALLT)
{case SQLUDF_TF_FIRST:
sp->p = fopen(fileName,"rb,type=record");
if (sp->p == NULL)
{ strcpy( SQLUDF_STATE, "38700");
sprintf (errMsg, "data set cannot be opened", fileName);
strcpy( SQLUDF_MSGTX, errMsg);
break;}
if (fldata(sp->p, filenameTmp, &fileinfo)) /*2*/
{ strcpy( SQLUDF_STATE, "38701");
strcpy( SQLUDF_MSGTX,"fldata() failed");
fclose(sp->p);
break; }
if ((fileinfo.__dsorgVSAM == 1 && /*3*/
(fileinfo.__vsamtype != __KSDS_PATH &&
fileinfo.__vsamtype != __ESDS_PATH &&
fileinfo.__vsamtype != __KSDS)) ||
( fileinfo.__dsorgVSAM != 1))
{ strcpy( SQLUDF_STATE, "38702");
strcpy( SQLUDF_MSGTX,"No VSAM KSDS");
fclose(sp->p);
break; }
sp->vsamkeylen = fileinfo.__vsamkeylen; /*4*/
sp->vsamRKP = fileinfo.__vsamRKP ;
if (flocate(sp->p,VSAMkey,sp->vsamkeylen,__KEY_EQ)) /*5*/
{ strcpy( SQLUDF_STATE, "38703");
sprintf (SQLUDF_MSGTX,"VSAMkey %s length %d not found",
VSAMkey,sp->vsamkeylen);
fclose(sp->p); break; }
case SQLUDF_TF_OPEN:
break;
case SQLUDF_TF_FETCH:
num = fread(clob32600->data ,1, 32600, sp->p) ;
if ((num == 0) ||
(memcmp(clob32600->data+sp->vsamRKP,Keyend,sp->vsamkeylen)>0)) /*6*/
{ strcpy( SQLUDF_STATE, "02000"); break; }
clob32600->length = num ; *clob32600IND = 0;
break;
case SQLUDF_TF_CLOSE:
fclose(sp->p); break;
case SQLUDF_TF_FINAL:
break;
}
}
|
Para o processamento de leitura aleatória de VSAM, as mudanças descritas abaixo foram implementados na UDF de tabela ReadFile: - A interface UDF fornece dois parâmetros adicionais: chave de início e de fim.
- O API fldata() recupera as informações do conjunto de dados que incluem os atributos VSAM.
- Se o tipo do conjunto de dados não suporta acesso sequencial a chave (apenas KSDS e VSAM PATH são suportados), SQLSTATE 38702 é retornado para o DB2 para z/OS.
- O comprimento da chave e as informações de deslocamento de registro de chave obtidas pelo API fldata são salvos na área de rascunho.
- Posicione o ponteiro do registro atual na chave de início.
- Se for alcançado o fim do arquivo (EOF) ou se a leitura de registro ficar além do valor da chave de fim, SQLSTATE 02000 será retornado para o DB2 para z/OS.
É possível instalar o programa UDF no DB2 para z/OS executando o procedimento JCL que é explicado na seção Criando user-defined functions deste artigo. A versão com sequencial de chave habilitado para VSAM da UDF de tabela ReadFile foi definida com os parâmetros mostrados na Listagem 17. Listagem 17. UDF de tabela ReadFile DDL VSAM
CREATE FUNCTION
C.READFILE(DSN CHAR(255), /*1*/
KEYSTART DECIMAL(15,0), /*2*/
KEYEND DECIMAL(15,0)) /*3*/
RETURNS TABLE
(FILERECORD VARCHAR(32600 )) /*4*/
|
A seguir, uma explicação dos parâmetros usados na Listagem 17: DSN — parâmetros de entrada para fornecer o nome do conjunto de dados z/OS ou do arquivo USS
KEYSTART — valor da chave de início para a leitura aleatória de VSAM
KEYEND — valor da chave de fim para a leitura aleatória de VSAM
FILERECORD — estrutura da tabela de resultados Requisito para UDFs escalares adicionais
Como ilustrado na Figura 11, o conjunto de dados VSAM armazena valores DECIMAL e SMALLINT em formato binário interno (veja os as informações de comprimento dos campos AccountID, Debit, Credit e Description VARCHAR). Figura 11. Estrutura de registro VSAM de detalhes da conta  É possível criar e preencher o conjunto de dados VSAM mostrado na Figura 11 executando o utilitário IDCAMS VSAM Access Method Services. Uma amostra de linguagem de controle de tarefa (JCL) IDCAMS e os dados de detalhes da conta usados nesse cenário são fornecidos no arquivo DWSReadFile.zip, cujo link se encontra na seção Downloads. O procedimento AccountDetail SQL transforma os formatos binários internos mostrados na Figura 11 em seus correspondentes em formatos de coluna DECIMAL e SMALLINT do DB2 para z/OS. Visto que o DB2 para z/OS não fornece função de conversão a partir de valores CHAR/VARCHAR armazenados em formato binário interno para formato de coluna INTEGER/DECIMAL do DB2 para z/OS, as UDFs escalares são usadas no procedimento AccountDetail SQL, como mostrado na Tabela 3.
Tabela 3. UDFs escalares adicionais
|
Nome da UDF
|
Parâmetro de Entrada
|
Valor de Retorno Escalar
|
|---|
| RF.BIGINT | VARCHAR(8) | BIGINT | | RF.DEC0 | VARCHAR(8) | DECIMAL(15,0) | | RF.DEC2 | VARCHAR(8) | DECIMAL(15,2) |
As funções escalares RF.BIGINT, RF.DEC0 e RF.DEC2 são implementadas pelo READCAST de programa C. O código de origem C do programa UDF é fornecido no arquivo DWSReadFile.zip, cujo link se encontra na seção Downloads. Modificações do procedimento armazenado AccountDetail
O procedimento armazenado AccountDetail usado na Parte 1 desta série de artigos foi alterado como mostrado na Listagem 18.
Listagem 18. Procedimento AccountDetail SQL com invocação ReadFile
CREATE PROCEDURE RF.ACCOUNTDETAIL
(INOUT ACCOUNTID DECIMAL(15, 0), OUT DOB DATE, OUT CUSTNAME VARCHAR(32) )
VERSION V001 ISOLATION LEVEL UR RESULT SETS 1 LANGUAGE SQL
P1:BEGIN
DECLARE DOB_TMP DATE DEFAULT 2009-03-20;
DECLARE CUSTNAME_TMP VARCHAR(32) DEFAULT ;
DECLARE ACCOUNTID_TMP DECIMAL(15,0);
DECLARE CURSOR1 CURSOR WITH RETURN FOR
WITH
QRY1 (RECORD) AS
(SELECT FILERECORD FROM
TABLE (C.READFILK /*1*/
(CHAR(//JOSEF.DWSUDFRD.ACCTNO.PATH), /*2*/
ACCOUNTID, /*3*/
ACCOUNTID)) A), /*4*/
QRY2 (ACCTNO, BOOK_DATE, DEBIT, CREDIT, DSC) AS
(SELECT /*5*/
RF.DEC0(SUBSTR(RECORD,01,08))
,DATE(SUBSTR(RECORD,10,10))
,RF.DEC2(SUBSTR(RECORD,21,08))
,RF.DEC2(SUBSTR(RECORD,30,08))
,VARCHAR(SUBSTR(RECORD,41,INTEGER(RF.BIGINT(SUBSTR(RECORD,39,02)))))
FROM QRY1)
SELECT * FROM QRY2;
-- Cursor left open for client application
OPEN CURSOR1;
SELECT
STRIP(SUBSTR(NM,1,POSSTR(NM,,)-1)) CONCAT , CONCAT
STRIP(SUBSTR(NM,POSSTR(NM,,)+1,LENGTH(NM)-POSSTR(NM,,))),
BRTH_DT INTO CUSTNAME_TMP,DOB_TMP
FROM ACCT.IP A
WHERE A.IP_ID IN
(SELECT IP_ID FROM ACCT.AR WHERE AR_ID = ACCOUNTID FETCH FIRST ROW ONLY);
SET ACCOUNTID_TMP = ACCOUNTID;
SET DOB = DOB_TMP;
SET CUSTNAME = CUSTNAME_TMP;
SET ACCOUNTID = ACCOUNTID_TMP;
END P1
|
A seguir, as principais mudanças feitas: - Uma expressão de tabela comum (CTE) de DB2 para z/OS invoca a UDF de tabela ReadFile para processamento de leitura aleatória de VSAM.
- O nome do conjunto de dados VSAM é passado como parâmetro de entrada.
- A chave de início é passada como parâmetro de entrada.
- A chave de fim é passada como parâmetro de entrada.
- Dentro da mesma CTE, as funções integradas do DB2 para z/OS e as UDFs escalares são usadas para mapear a estrutura do campo de registro do conjunto de dados na coluna da tabela de resultados.
Criando e implementando o AccountInquiry DWS
Agora, com a UDF de tabela ReadFile habilitada para operações de leitura sequencial de chave VSAM e o procedimento AccountDetail SQL modificado para usar essa UDF de tabela ReadFile, é possível recriar o AccountInquiry DWS e recriar e reimplementar o arquivo WAR no seu ambiente de servidor de aplicativos J2EE. Para isso, execute as seguintes tarefas de implementação no Optim Development Studio (ou Data Studio): - No projeto UDFReadFile existente, crie o projeto de Web Services AccountInquiry_VSAM.
- Arraste e solte os procedimentos AccountSummary e ListCustomer SQL existentes que foram usados na Parte 1 desta série de artigos para o projeto de Web Services AccountInquiry_VSAM.
- Arraste e solte o procedimento AccountDetail SQL mostrado na Listagem 18 para o projeto de Web Services AccountInquiry_VSAM.
- Use as folhas de estilo XSLT fornecidas na Parte 1 deste artigo para ativar a mensagem de saída XSLT para transformação HTML para as operações de serviço da Web ListCustomer, AccountSummary e AccountDetail.
- Crie o arquivo Web Application Archive AccountInquiry_VSAM (arquivo WAR).
- Instale o arquivo WAR AccountInquiry_VSAM no seu ambiente do servidor de aplicativo J2EE.
Executando o aplicativo AccountInquiry_VSAM baseado em HTML
Após instalar com êxito o aplicativo AccountInquiry_VSAM, ele usa o procedimento AccountDetail SQL modificado para acessar o conjunto de dados VSAM com detalhes da conta por meio da UDF de tabela ReadFile. É possível invocar a operação de serviço da Web ListCustomer usando uma URL HTTP estilo REST do mesmo modo descrito na Parte 1 desta série de artigos. Embora as informações de detalhes da conta sejam agora recuperadas do conjunto de dados VSAM, não se notará nenhuma diferença — exceto a URL HTTP. A invocação retorna a página da Web baseada em HTML mostrada na Figura 12. Figura 12. ListCustomer XSLT transformada em página da Web HTML  Na página mostrada na Figura 12, clique em Número de Cliente 36505633552 para ver as informações de resumo da conta daquele cliente, como mostrado na Figura 13. Figura 13. AccountSummary XSLT transformada em página da Web HTML  Na página mostrada na Figura 13, clique em Número da Conta 9000000002 para ver as informações de detalhes daquele número de conta, como mostrado na Figura 14. Figure 14. AccountDetail XSLT transformada em página da Web HTML 
Conclusão
User-defined functions, como as descritas neste artigo, fornecem um modo fácil de acessar arquivos e conjuntos de dados a partir do SQL. Depois que os arquivos e conjuntos de dados estão acessíveis a partir do SQL, é possível usar funções integradas do SQL existentes e suas próprias UDFs para executar manipulação de dados nas informações armazenadas nos conjuntos de dados e arquivos. Também é possível expor essas instruções SQL "de leitura de arquivo" como IBM Data Web Services. Desse modo os conjuntos de dados e arquivos ficam disponíveis para operações de serviços da Web.
Downloads | Descrição | Nome | Tamanho | Método de download |
|---|
| Sample code for this article | DWSReadFile.zip | 209KB | HTTP |
|---|
| Data Studio project for this article | UDFReadFile.zip | 505KB | HTTP |
|---|
Recursos Aprender
Obter produtos e tecnologias
Discutir
Sobre o autor  | 
|  | Josef Klitsch é Especialista em TI em IBM Software Services, atualmente designado para o IBM PSSC Montpellier, New Technology Center. Josef fornece serviços de consultoria relacionados ao DB2 para z/OS. Você pode entrar em contato com ele pelo e-mail josef.klitsch@ch.ibm.com. |
Avalie esta página
|  |