Translate

domingo, 23 de janeiro de 2022

SPUFI sem Mistérios: do Primeiro SELECT ao Dataset de Saída no Db2 for z/OS

 

Bellacosa Mainframe e o spufi sem misterios

☕ Um Café no Bellacosa Mainframe

SPUFI sem Mistérios: do Primeiro SELECT ao Dataset de Saída no Db2 for z/OS

O guia do programador COBOL Padawan para entender SQL, datasets, isolamento, CCSID, commit, JCL e tudo o que acontece por trás da tela verde

Imagine a cena.

Você acabou de entrar no TSO, abriu o ISPF, navegou até o DB2I e escolheu a opção SPUFI. Diante de você aparece aquela clássica tela preta, com letras verdes e azuis, campos numerados e algumas opções que parecem inocentes:

EDIT INPUT  . . . . ===> YES
EXECUTE . . . . . . ===> YES
AUTOCOMMIT . . . . . ===> YES
BROWSE OUTPUT  . . . ===> YES

O programador COBOL Padawan olha para aquilo e pensa:

“Eu só queria executar um SELECT. Por que preciso informar dataset, volume, senha, isolamento, formato, espaço primário, espaço secundário, LRECL, BLKSIZE e CCSID?”

Essa pergunta é perfeita.

Ela revela uma diferença fundamental entre o mundo distribuído e o universo IBM Mainframe.

Em muitas ferramentas modernas, você abre uma janela, digita SQL e recebe o resultado em uma grade gráfica. No z/OS, entretanto, cada etapa foi construída para ser explícita, controlável, auditável e reutilizável. O SPUFI não trabalha apenas com uma “caixa de texto”. Ele trabalha com datasets reais, parâmetros de execução, formatos de registro, controle transacional e integração direta com o subsistema Db2.

O SPUFI é simples na aparência, mas por trás daquela tela existe uma pequena cadeia de processamento digna de uma aplicação batch.

Prepare o café, abra o caderno de anotações e ajuste os óculos de programador Jedi. Vamos desmontar o SPUFI peça por peça.


Bellacosa Mainframe o que é o Spufi?

1. O que é SPUFI?

SPUFI significa:

SQL Processor Using File Input

Em uma tradução livre:

Processador SQL usando um arquivo como entrada.

Esse nome descreve exatamente o que a ferramenta faz.

O SPUFI:

  1. lê comandos SQL de um dataset;

  2. envia esses comandos ao Db2;

  3. recebe o resultado;

  4. grava as mensagens e linhas retornadas em outro dataset;

  5. opcionalmente abre o resultado para consulta.

Seu fluxo básico é:

Programador
    |
    v
Dataset com SQL
    |
    v
SPUFI
    |
    v
Plano/Pacote do DB2I
    |
    v
Subsistema Db2
    |
    v
Parser + Otimizador + Executor
    |
    v
Dataset de saída

Perceba um detalhe importante: o SPUFI não é o banco de dados, nem o otimizador e nem o mecanismo responsável por acessar as tabelas.

Ele é uma interface.

Quem realmente valida, otimiza e executa o SQL é o Db2.


2. Por que o SPUFI continua importante?

Mesmo existindo ferramentas gráficas, IDEs, plugins para VS Code, interfaces web e utilitários distribuídos, o SPUFI continua extremamente útil porque:

  • executa SQL diretamente dentro do ambiente z/OS;

  • usa a autenticação do usuário TSO;

  • acessa o subsistema Db2 local;

  • não depende de configuração ODBC ou JDBC externa;

  • grava a entrada e a saída em datasets;

  • facilita auditoria e repetição dos testes;

  • funciona bem em ambientes restritos;

  • é familiar para DBAs, sysprogs e desenvolvedores veteranos.

Além disso, o SPUFI é uma excelente escola.

Quem aprende SPUFI acaba aprendendo, mesmo sem perceber:

  • PDS e membros;

  • datasets sequenciais;

  • atributos DCB;

  • alocação em DASD;

  • CCSID;

  • terminadores SQL;

  • níveis de isolamento;

  • commits;

  • planos e pacotes;

  • códigos SQL;

  • organização de scripts.

Portanto, o SPUFI não é apenas uma ferramenta antiga. Ele é uma ponte entre SQL e a cultura operacional do mainframe.


3. A primeira tela: o painel principal do SPUFI

Na tela mostrada, temos algo semelhante a:

SPUFI                                         SSID: DB9G

Enter the input data set name:
 1 DATA SET NAME ... ===> 'IBMUSER.WORKBOOK.SQL(SELCOPA)'
 2 VOLUME SERIAL .... ===>
 3 DATA SET PASSWORD  ===>

Enter the output data set name:
 4 DATA SET NAME ... ===> 'INEFE00.OUTPUT.SAIDA'

Specify processing options:
 5 CHANGE DEFAULTS .. ===> YES
 6 EDIT INPUT ....... ===> YES
 7 EXECUTE .......... ===> YES
 8 AUTOCOMMIT ....... ===> YES
 9 BROWSE OUTPUT .... ===> YES

For remote SQL processing:
10 CONNECT LOCATION . ===>

No canto superior direito aparece:

SSID: DB9G

SSID significa Subsystem Identifier.

É o identificador do subsistema Db2 ao qual o DB2I está conectado.

Em uma instalação, podem existir vários subsistemas:

DB2D   Desenvolvimento
DB2T   Testes
DB2H   Homologação
DB2P   Produção
DB9G   Laboratório ou ambiente específico

O nome não possui significado universal. Cada empresa define sua convenção.

Um Padawan deve sempre observar o SSID antes de executar qualquer comando destrutivo.

Um DELETE no ambiente errado pode transformar uma aula tranquila em uma reunião extraordinária com DBA, gestor, auditoria, segurança e provavelmente alguém perguntando por que não havia WHERE.


4. Campo 1 — DATA SET NAME de entrada

No exemplo:

'IBMUSER.WORKBOOK.SQL(SELCOPA)'

Esse nome possui duas partes:

IBMUSER.WORKBOOK.SQL

É o dataset.

SELCOPA

É o membro.

Isso indica que o dataset provavelmente é um PDS ou PDSE.

Podemos visualizá-lo como uma pasta:

IBMUSER.WORKBOOK.SQL
   |
   +-- SELCOPA
   +-- SELCLIENT
   +-- UPDTEST
   +-- CREATE01
   +-- JOIN001

Cada membro contém um ou mais comandos SQL.

Por exemplo, o membro SELCOPA pode conter:

SELECT EMPNO,
       FIRSTNME,
       LASTNAME,
       WORKDEPT
  FROM DSN8C10.EMP
 WHERE WORKDEPT = 'A00'
 ORDER BY LASTNAME;

Por que usar um PDS ou PDSE?

Porque ele permite organizar vários scripts dentro do mesmo dataset.

Uma estrutura interessante seria:

IBMUSER.DB2.SQL
   |
   +-- SEL001
   +-- SEL002
   +-- INS001
   +-- UPD001
   +-- DEL001
   +-- DDL001
   +-- EXPLAIN
   +-- CATALOG

É como possuir uma biblioteca de scripts SQL, só que usando a estrutura tradicional do z/OS.

PDS ou PDSE?

Os dois funcionam, mas o PDSE costuma ser preferível em ambientes modernos porque:

  • não exige compressão;

  • reutiliza espaço interno de forma mais eficiente;

  • possui melhor gerenciamento de diretório;

  • reduz alguns problemas clássicos de fragmentação.


5. Criando o dataset de entrada

Você pode criar o dataset pelo ISPF 3.2 ou por JCL.

Exemplo:

//CRIASQL  JOB (ACCT),'CRIA PDS SQL',
//             CLASS=A,
//             MSGCLASS=X,
//             NOTIFY=&SYSUID
//*
//ALLOC    EXEC PGM=IEFBR14
//SQLLIB   DD  DSN=IBMUSER.WORKBOOK.SQL,
//             DISP=(NEW,CATLG,DELETE),
//             UNIT=SYSDA,
//             SPACE=(TRK,(2,2,20)),
//             DCB=(DSORG=PO,RECFM=FB,LRECL=80,BLKSIZE=0)
//

Agora vamos explicar cada linha.

JOB

//CRIASQL  JOB (ACCT),'CRIA PDS SQL',

Define o início do job.

  • CRIASQL é o nome do job;

  • (ACCT) é a informação contábil;

  • 'CRIA PDS SQL' é uma descrição.

CLASS

//             CLASS=A,

Indica a classe de execução.

A classe controla aspectos como:

  • fila;

  • prioridade;

  • recursos;

  • regras locais de execução.

MSGCLASS

//             MSGCLASS=X,

Indica a classe de saída das mensagens JES.

NOTIFY

//             NOTIFY=&SYSUID

Solicita que o usuário que submeteu o job seja notificado quando ele terminar.

EXEC PGM=IEFBR14

//ALLOC    EXEC PGM=IEFBR14

IEFBR14 é um programa praticamente vazio, tradicionalmente usado para permitir que o sistema processe instruções DD.

Ele não “cria” o dataset diretamente. Quem faz a alocação é o gerenciamento de datasets do z/OS ao interpretar a DD com DISP=NEW.

Esse é um dos grandes easter eggs do mainframe: um programa que praticamente não faz nada tornou-se uma das peças mais famosas do JCL.

DSN

//SQLLIB   DD  DSN=IBMUSER.WORKBOOK.SQL,

Define o nome do dataset.

DISP

//             DISP=(NEW,CATLG,DELETE),

Significa:

  • NEW: o dataset será criado;

  • CATLG: se o step terminar normalmente, será catalogado;

  • DELETE: se houver falha, será excluído.

UNIT

//             UNIT=SYSDA,

Solicita uma unidade DASD genérica.

SPACE

//             SPACE=(TRK,(2,2,20)),

Significa:

  • unidade de alocação: tracks;

  • espaço primário: 2 tracks;

  • espaço secundário: 2 tracks;

  • diretório: 20 blocos.

O terceiro valor é relevante porque o dataset é particionado.

DCB

//             DCB=(DSORG=PO,RECFM=FB,LRECL=80,BLKSIZE=0)
  • DSORG=PO: organização particionada;

  • RECFM=FB: registros fixos blocados;

  • LRECL=80: cada registro possui 80 bytes;

  • BLKSIZE=0: o sistema escolhe um tamanho de bloco adequado.

O formato FB 80 é clássico para código-fonte, JCL e scripts SQL.


6. Campo 2 — VOLUME SERIAL

VOLUME SERIAL ===>

Esse campo normalmente fica em branco quando o dataset está catalogado.

O catálogo do z/OS já informa em qual volume ele reside.

Você só precisa preencher o VOLSER quando trabalha com um dataset não catalogado ou quando há uma razão operacional específica.

Exemplo:

VOLUME SERIAL ===> VOL001

Na maioria dos ambientes modernos, deixar em branco é correto.


7. Campo 3 — DATA SET PASSWORD

DATA SET PASSWORD ===>

Esse campo remete a mecanismos antigos de proteção por senha de dataset.

Atualmente, o acesso normalmente é controlado por um produto de segurança como:

  • RACF;

  • ACF2;

  • Top Secret.

Em ambientes modernos, esse campo quase sempre permanece vazio.

É quase uma peça arqueológica viva: continua presente porque o mainframe preserva compatibilidade com décadas de história.


8. Campo 4 — dataset de saída

No exemplo:

'INEFE00.OUTPUT.SAIDA'

A tela informa:

Must be a sequential data set

Isso significa que o dataset de saída deve ser sequencial.

O SPUFI grava:

  • o SQL executado;

  • mensagens do Db2;

  • SQLCODE;

  • SQLSTATE;

  • linhas retornadas;

  • quantidade de registros;

  • informações de commit;

  • eventuais erros.

Exemplo de saída:

---------+---------+---------+---------+---------+---------

SELECT EMPNO, FIRSTNME, LASTNAME
FROM DSN8C10.EMP
WHERE WORKDEPT = 'A00';

EMPNO  FIRSTNME     LASTNAME
------ ------------ ---------------
000010 CHRISTINE    HAAS
000110 VINCENZO     LUCCHESSI
000120 SEAN         O'CONNELL

DSNE610I NUMBER OF ROWS DISPLAYED IS 3
DSNE616I STATEMENT EXECUTION WAS SUCCESSFUL, SQLCODE IS 0

Criando o dataset de saída

//CRIAOUT  JOB (ACCT),'CRIA SAIDA SPUFI',
//             CLASS=A,
//             MSGCLASS=X,
//             NOTIFY=&SYSUID
//*
//ALLOC    EXEC PGM=IEFBR14
//OUTPUT   DD  DSN=IBMUSER.OUTPUT.SPUFI,
//             DISP=(NEW,CATLG,DELETE),
//             UNIT=SYSDA,
//             SPACE=(TRK,(5,5)),
//             DCB=(DSORG=PS,RECFM=VB,LRECL=4092,BLKSIZE=0)
//

Aqui temos:

DSORG=PS

Physical Sequential, ou seja, sequencial.

RECFM=VB

Registros variáveis e blocados.

LRECL=4092

Permite linhas grandes de saída.

BLKSIZE=0

O sistema calcula um valor apropriado.


9. Campo 5 — CHANGE DEFAULTS

CHANGE DEFAULTS ===> YES

Com YES, o SPUFI abre a tela de parâmetros padrão.

Com NO, utiliza os valores já salvos no perfil do usuário ou na configuração da instalação.

Essa opção é útil quando você precisa alterar:

  • nível de isolamento;

  • número máximo de linhas;

  • terminador SQL;

  • atributos do dataset de saída;

  • largura das colunas;

  • formato dos cabeçalhos.

Para uma consulta simples, você pode usar NO.

Para aprender ou ajustar comportamento, use YES.


10. Campo 6 — EDIT INPUT

EDIT INPUT ===> YES

Com YES, o SPUFI abre o membro de entrada no editor ISPF antes da execução.

O fluxo será:

SPUFI
  |
  +--> abre ISPF Edit
  |
  +--> você grava o SQL
  |
  +--> pressiona PF3
  |
  +--> SPUFI executa

Com NO, ele executa diretamente o conteúdo atual do dataset.

Isso é útil quando o script já está pronto e não precisa ser revisado.

Exemplo de SQL para iniciantes

SELECT CURRENT DATE,
       CURRENT TIME,
       CURRENT TIMESTAMP
  FROM SYSIBM.SYSDUMMY1;

A tabela SYSIBM.SYSDUMMY1 é uma tabela especial com uma única linha, muito usada para testar expressões.

É o equivalente Db2 de uma pequena bancada de laboratório.


11. Campo 7 — EXECUTE

EXECUTE ===> YES

Com YES, o SQL será enviado ao Db2.

Com NO, o SPUFI pode permitir que você apenas edite o input sem executar.

Parece inútil, mas é interessante quando o SPUFI está sendo usado apenas como uma forma rápida de localizar e modificar um membro SQL.


12. Campo 8 — AUTOCOMMIT

AUTOCOMMIT ===> YES

Esse é um dos campos mais perigosos da tela.

Com YES, o SPUFI confirma automaticamente uma unidade de trabalho bem-sucedida.

Exemplo:

UPDATE CORP.CLIENTE
   SET STATUS = 'I'
 WHERE CLIENTE_ID = 100;

Se o comando funcionar e AUTOCOMMIT=YES, a alteração será confirmada.

Um ROLLBACK posterior não desfará essa atualização.

Para SELECT

Em consultas, o risco é pequeno.

Para INSERT, UPDATE e DELETE

Atenção máxima.

Durante testes, uma prática mais segura é:

AUTOCOMMIT ===> NO

E incluir comandos explícitos:

UPDATE CORP.CLIENTE
   SET STATUS = 'I'
 WHERE CLIENTE_ID = 100;

SELECT CLIENTE_ID,
       STATUS
  FROM CORP.CLIENTE
 WHERE CLIENTE_ID = 100;

ROLLBACK;

Assim você verifica o resultado e depois desfaz.

Quando estiver absolutamente certo:

UPDATE CORP.CLIENTE
   SET STATUS = 'I'
 WHERE CLIENTE_ID = 100;

COMMIT;

Cuidado especial com DELETE

Nunca execute casualmente:

DELETE FROM CORP.CLIENTE;

Sem WHERE, todas as linhas elegíveis podem ser removidas.

Antes de executar um DELETE, transforme-o em SELECT:

SELECT *
  FROM CORP.CLIENTE
 WHERE STATUS = 'I';

Confira a quantidade.

Depois:

DELETE
  FROM CORP.CLIENTE
 WHERE STATUS = 'I';

Esse pequeno ritual salva carreiras.


13. Campo 9 — BROWSE OUTPUT

BROWSE OUTPUT ===> YES

Com YES, o dataset de saída é aberto automaticamente após a execução.

Com NO, o resultado é gravado, mas você precisará abri-lo manualmente.

Por exemplo, usando:

ISPF 3.4

ou um comando:

BROWSE 'IBMUSER.OUTPUT.SPUFI'

Usar YES é conveniente para testes interativos.

Usar NO pode ser útil quando o resultado é muito grande ou quando o processamento será revisado posteriormente.


14. Campo 10 — CONNECT LOCATION

CONNECT LOCATION ===>

Esse campo permite direcionar a execução para uma localização Db2 remota.

Em ambientes distribuídos, o Db2 pode usar DRDA para comunicação entre subsistemas.

Exemplo conceitual:

Db2 local DB2D
     |
     | DRDA
     v
Db2 remoto DB2P

O valor usado depende da configuração de localização no catálogo Db2.

Para consultas locais, deixe em branco.


15. O aviso DSNE345I e a guerra dos CCSIDs

Na segunda tela aparece:

DSNE345I WARNING: DB2 DATA CORRUPTION CAN RESULT
FROM THIS SPUFI SESSION BECAUSE THE
CCSID USED BY THE TERMINAL IS NOT THE
SAME AS THE CCSID USED BY SPUFI

TERMINAL CCSID: 37
SPUFI CCSID   : 1047

Esse não é um simples aviso cosmético.

CCSID significa:

Coded Character Set Identifier

Ele identifica a tabela de codificação de caracteres.

No mundo z/OS, “EBCDIC” não é uma única tabela universal. Existem diferentes variantes.

Entre elas:

  • CCSID 37;

  • CCSID 500;

  • CCSID 1047;

  • CCSID 1140.

O terminal está usando CCSID 37, enquanto o SPUFI espera 1047.

Caracteres alfabéticos simples podem aparecer corretamente, mas símbolos especiais podem ocupar posições diferentes.

Os maiores suspeitos são caracteres como:

[
]
{
}
|
\
^
~

Imagine uma expressão SQL com texto:

INSERT INTO TESTE.TABELA
       (DESCRICAO)
VALUES ('ARQUIVO [TEMP]');

Se houver conversão incorreta, os colchetes podem ser gravados como outros símbolos.

Em um SELECT, você pode apenas ver uma saída estranha.

Em um INSERT ou UPDATE, porém, dados incorretos podem ser persistidos.

O que fazer?

O aviso diz:

NOTIFY THE DB2 SYSTEM ADMINISTRATOR

Isso significa que a solução definitiva normalmente envolve revisar:

  • configuração do emulador 3270;

  • code page da sessão;

  • parâmetros do DB2I;

  • CCSID do subsistema;

  • perfil do usuário;

  • configuração do SPUFI.

No emulador TN3270, procure opções relacionadas a:

  • host code page;

  • EBCDIC code page;

  • character set;

  • CCSID;

  • language;

  • keyboard mapping.

Não altere aleatoriamente em produção. Uma mudança incorreta pode resolver um símbolo e quebrar outro.


16. A tela CURRENT SPUFI DEFAULTS

A terceira tela apresenta os parâmetros internos do SPUFI.

CURRENT SPUFI DEFAULTS

Vamos examinar cada um.


17. SQL TERMINATOR

SQL TERMINATOR ===> ;

O ponto e vírgula indica o fim de cada instrução SQL.

Exemplo:

SELECT COUNT(*)
  FROM SYSIBM.SYSTABLES;

Vários comandos:

SELECT CURRENT DATE
  FROM SYSIBM.SYSDUMMY1;

SELECT CURRENT TIME
  FROM SYSIBM.SYSDUMMY1;

Alterando o terminador

Em alguns scripts, especialmente com rotinas SQL PL, o ponto e vírgula também aparece dentro de blocos.

Pode ser conveniente trocar o terminador externo:

SQL TERMINATOR ===> #

Então:

CREATE PROCEDURE TESTE.PROC1()
LANGUAGE SQL
BEGIN
    INSERT INTO TESTE.LOG
    VALUES (CURRENT TIMESTAMP);

    UPDATE TESTE.CONTROLE
       SET STATUS = 'F';
END
#

O # encerra a instrução completa, enquanto os pontos e vírgulas continuam dentro do bloco.


18. ISOLATION LEVEL

Na tela:

ISOLATION LEVEL ===> CS

Os valores mais comuns são:

UR
CS
RS
RR

UR — Uncommitted Read

É a leitura com menor compromisso de consistência.

Permite ler dados que outra transação modificou, mas ainda não confirmou.

Exemplo:

SELECT *
  FROM CORP.MOVIMENTO
 WITH UR;

Vantagens:

  • poucos locks;

  • boa concorrência;

  • útil para relatórios não críticos.

Riscos:

  • dirty read;

  • dados podem desaparecer após rollback;

  • totais podem não representar um estado confirmado.

Use UR para consultas informativas, nunca como base cega para decisões financeiras ou atualizações dependentes.

CS — Cursor Stability

É o valor mostrado na tela.

O Db2 protege a linha atualmente posicionada pelo cursor e libera locks conforme a navegação, dependendo do plano e da execução.

É um bom equilíbrio entre:

  • consistência;

  • concorrência;

  • desempenho.

É muito comum em aplicações online.

RS — Read Stability

Garante maior estabilidade para as linhas qualificadas já lidas.

Evita que elas sejam modificadas de forma conflitante durante a unidade de trabalho.

Pode manter mais locks.

RR — Repeatable Read

É o nível mais restritivo.

A mesma consulta dentro da unidade de trabalho tende a reencontrar um conjunto estável de linhas, de acordo com as regras do isolamento.

Pode gerar:

  • muitos locks;

  • contenção;

  • timeout;

  • deadlock;

  • escalonamento de locks.

Comparação conceitual

IsolamentoConsistênciaConcorrênciaLocks
URbaixamuito altamínimos
CSequilibradaaltamoderados
RSaltamédiamaiores
RRmuito altamenorelevados

19. MAX SELECT LINES

MAX SELECT LINES ===> 250

Esse parâmetro limita a quantidade de linhas exibidas pelo SPUFI.

Ele funciona como um cinto de segurança.

Imagine:

SELECT *
  FROM SYSIBM.SYSCOLUMNS;

Dependendo do ambiente, isso pode retornar milhares de linhas.

O SPUFI interrompe a exibição ao atingir o limite configurado.

Atenção: isso não significa necessariamente que o Db2 sempre acessará apenas 250 linhas em todas as circunstâncias. O limite controla principalmente o processamento e apresentação do resultado pelo SPUFI.

Para consultas grandes, prefira filtros:

SELECT NAME,
       CREATOR,
       TYPE
  FROM SYSIBM.SYSTABLES
 WHERE CREATOR = 'IBMUSER'
 ORDER BY NAME;

20. ALLOW SQL WARNINGS

ALLOW SQL WARNINGS ===> NO

SQL warnings são avisos que não representam necessariamente falha fatal.

O SQLCA pode trazer:

SQLCODE positivo

Exemplos comuns incluem:

  • truncamento;

  • eliminação de valores nulos em agregações;

  • nenhuma linha em certas operações;

  • condições especiais de processamento.

Com NO, o SPUFI pode interromper ou tratar de maneira mais conservadora.

Com YES, ele pode continuar buscando linhas após avisos.

Para aprendizado, deixar NO ajuda a perceber que algo especial ocorreu.


21. CHANGE PLAN NAMES

CHANGE PLAN NAMES ===> NO

O SPUFI executa sob estruturas Db2 previamente definidas, incluindo planos e pacotes do DB2I.

Essa opção permite trabalhar com nomes alternativos em configurações específicas.

Para o programador iniciante, a recomendação é manter:

NO

Alterar planos exige conhecimento de:

  • BIND;

  • PACKAGE;

  • PLAN;

  • COLLECTION;

  • autorização;

  • compatibilidade do ambiente.


22. SQL FORMAT

SQL FORMAT ===> SQL

Esse campo define o tratamento do conteúdo SQL.

As opções podem variar conforme versão e configuração, mas geralmente distinguem formatos como:

  • SQL convencional;

  • SQL com comentários;

  • SQL PL.

Para consultas normais:

SQL

é suficiente.


23. SPACE UNIT

SPACE UNIT ===> TRK

Define a unidade usada para alocar o dataset de saída.

Valores comuns:

TRK
CYL

TRK significa track.

CYL significa cylinder.

Para resultados pequenos, tracks são suficientes.

Para saídas muito grandes, cylinders podem ser mais apropriados.


24. PRIMARY SPACE e SECONDARY SPACE

PRIMARY SPACE   ===> 6
SECONDARY SPACE ===> 5

O espaço primário é alocado inicialmente.

O secundário é solicitado quando o espaço inicial se esgota.

Neste exemplo:

SPACE=(TRK,(6,5))

Conceitualmente:

  • aloque 6 tracks inicialmente;

  • quando necessário, expanda em blocos de 5 tracks.

Muitas extensões pequenas podem causar fragmentação e atingir limites de extents.

Por outro lado, uma alocação primária exagerada desperdiça espaço.

O tamanho ideal depende do volume esperado.


25. RECORD LENGTH

RECORD LENGTH ===> 4092

É o LRECL do dataset de saída.

Como o resultado pode incluir colunas extensas, o SPUFI usa registros largos.

Um VARCHAR(2000) ou a combinação de várias colunas pode exigir linhas grandes.

Se o LRECL for pequeno demais, a saída pode ser truncada ou a alocação pode falhar, dependendo do cenário.


26. BLOCK SIZE

BLOCK SIZE ===> 4096

O BLKSIZE indica o tamanho dos blocos físicos usados na gravação.

Blocos reduzem a quantidade de operações de I/O.

Em alocações modernas, frequentemente usamos:

BLKSIZE=0

para permitir que o sistema determine um valor eficiente.

Na tela do SPUFI, valores predefinidos podem ser usados conforme a configuração local.


27. RECORD FORMAT

RECORD FORMAT ===> VB

VB significa:

Variable Blocked

Os registros possuem tamanho variável e são agrupados em blocos.

Isso é apropriado para resultados SQL, porque uma linha pode ter 20 bytes e outra 800 bytes.

Outros formatos citados na tela:

F
FB
FBA
V
VB
VBA
  • F: fixo;

  • FB: fixo blocado;

  • FBA: fixo blocado com controle ASA;

  • V: variável;

  • VB: variável blocado;

  • VBA: variável blocado com controle ASA.


28. DEVICE TYPE

DEVICE TYPE ===> SYSDA

SYSDA é um nome genérico de unidade DASD.

O sistema e o SMS determinam o volume apropriado.

Em ambientes gerenciados por SMS, vários parâmetros físicos podem ser escolhidos automaticamente por classes de armazenamento.


29. MAX NUMERIC FIELD

MAX NUMERIC FIELD ===> 33

Define a largura máxima usada para apresentar campos numéricos.

Isso evita que números muito extensos destruam o alinhamento da saída.

Por exemplo:

SELECT DECIMAL(12345678901234567890,20,0)
  FROM SYSIBM.SYSDUMMY1;

A configuração controla quanto espaço poderá ser reservado para exibição.


30. MAX CHAR FIELD

MAX CHAR FIELD ===> 80

Define a largura máxima de apresentação das colunas de caracteres.

Imagine uma coluna:

DESCRICAO VARCHAR(1000)

Sem limite, uma única coluna tornaria a saída enorme.

Com máximo 80, a apresentação fica mais administrável.

Atenção: isso pode significar que você não verá todo o conteúdo visualmente na linha formatada.

Quando precisar analisar o valor integral, selecione a coluna isoladamente ou use funções como:

SELECT LENGTH(DESCRICAO),
       SUBSTR(DESCRICAO,1,200)
  FROM TESTE.PRODUTO;

31. COLUMN HEADING

COLUMN HEADING ===> NAMES

Opções comuns:

NAMES
LABELS
ANY
BOTH

NAMES

Usa o nome técnico da coluna.

CUST_ID
CUST_NAME

LABELS

Usa o label definido no catálogo, se existir.

Código do Cliente
Nome do Cliente

BOTH

Pode mostrar nome e label.

Para desenvolvedores, NAMES costuma ser mais útil porque corresponde ao SQL e ao DCLGEN.

Para relatórios destinados a usuários, labels podem ser mais amigáveis.


32. Primeiro laboratório SPUFI: SELECT simples

Crie um membro chamado TESTE01 com:

SELECT CURRENT SERVER    AS SERVIDOR,
       CURRENT DATE      AS DATA_ATUAL,
       CURRENT TIME      AS HORA_ATUAL,
       CURRENT TIMESTAMP AS TIMESTAMP_ATUAL
  FROM SYSIBM.SYSDUMMY1;

Configure:

EDIT INPUT     YES
EXECUTE        YES
AUTOCOMMIT     YES
BROWSE OUTPUT  YES

Pressione Enter.

O fluxo será:

  1. o SPUFI abre o editor;

  2. você confere o SQL;

  3. pressiona PF3;

  4. o Db2 recebe o comando;

  5. o parser verifica a sintaxe;

  6. o otimizador prepara a execução;

  7. a tabela especial é acessada;

  8. o resultado retorna;

  9. o SPUFI formata a saída;

  10. o dataset de saída é aberto.


33. Segundo laboratório: consultar o catálogo

SELECT CREATOR,
       NAME,
       TYPE
  FROM SYSIBM.SYSTABLES
 WHERE CREATOR = 'IBMUSER'
 ORDER BY NAME;

O catálogo Db2 é um conjunto de tabelas que descreve os objetos do banco.

Ele contém informações sobre:

  • tabelas;

  • colunas;

  • índices;

  • tablespaces;

  • pacotes;

  • planos;

  • privilégios;

  • estatísticas.

Consultar o catálogo é como abrir o mapa interno do reino Db2.


34. Terceiro laboratório: UPDATE seguro com ROLLBACK

SELECT CLIENTE_ID,
       STATUS
  FROM TESTE.CLIENTE
 WHERE CLIENTE_ID = 100;

UPDATE TESTE.CLIENTE
   SET STATUS = 'I'
 WHERE CLIENTE_ID = 100;

SELECT CLIENTE_ID,
       STATUS
  FROM TESTE.CLIENTE
 WHERE CLIENTE_ID = 100;

ROLLBACK;

SELECT CLIENTE_ID,
       STATUS
  FROM TESTE.CLIENTE
 WHERE CLIENTE_ID = 100;

Configure:

AUTOCOMMIT ===> NO

A sequência demonstra:

  1. estado inicial;

  2. alteração;

  3. estado dentro da unidade de trabalho;

  4. rollback;

  5. restauração do valor anterior.

Esse é um excelente laboratório para compreender transações.


35. Executando SQL no Db2 por JCL

O SPUFI é interativo, mas o SQL também pode ser executado em batch usando o utilitário DSNTEP2 ou DSNTEP4, dependendo da instalação.

Exemplo:

//SQLBATCH JOB (ACCT),'EXECUTA SQL',
//             CLASS=A,
//             MSGCLASS=X,
//             NOTIFY=&SYSUID
//*
//STEP01   EXEC PGM=IKJEFT01,DYNAMNBR=20
//STEPLIB  DD  DISP=SHR,DSN=DSN.V13R1M0.SDSNLOAD
//SYSTSPRT DD  SYSOUT=*
//SYSPRINT DD  SYSOUT=*
//SYSUDUMP DD  SYSOUT=*
//SYSTSIN  DD  *
  DSN SYSTEM(DB9G)
  RUN PROGRAM(DSNTEP2) PLAN(DSNTEP13) -
      LIB('DSN.V13R1M0.RUNLIB.LOAD')
  END
/*
//SYSIN    DD  *
SELECT CURRENT SERVER,
       CURRENT DATE,
       CURRENT TIME
  FROM SYSIBM.SYSDUMMY1;

SELECT COUNT(*) AS TOTAL_TABELAS
  FROM SYSIBM.SYSTABLES;
/*

IKJEFT01

//STEP01 EXEC PGM=IKJEFT01

IKJEFT01 permite executar comandos TSO em batch.

É como criar uma sessão TSO controlada pelo JCL.

DYNAMNBR

DYNAMNBR=20

Reserva capacidade para alocações dinâmicas.

STEPLIB

//STEPLIB DD DISP=SHR,DSN=DSN.V13R1M0.SDSNLOAD

Aponta para a biblioteca de load modules do Db2.

O nome real varia conforme a instalação.

SYSTSIN

DSN SYSTEM(DB9G)

Inicia o command processor do Db2 e conecta ao subsistema DB9G.

RUN PROGRAM(DSNTEP2)

Executa o programa DSNTEP2.

PLAN(DSNTEP13)

Informa o plano associado.

O nome também varia conforme versão e instalação.

LIB('DSN.V13R1M0.RUNLIB.LOAD')

Informa a biblioteca onde o programa será localizado.

SYSIN

Contém os comandos SQL.

Assim, a lógica lembra o SPUFI:

SPUFI                 DSNTEP2
------                -------
Dataset input         SYSIN
Execução interativa   Execução batch
Dataset output        SYSPRINT
Tela ISPF             JES/SDSF

36. JCL usando SQL em dataset externo

Em vez de escrever SQL dentro do JCL:

//SYSIN DD *
SELECT ...
/*

podemos usar um membro:

//SYSIN DD DISP=SHR,DSN=IBMUSER.WORKBOOK.SQL(SELCOPA)

Job completo:

//SQLBATCH JOB (ACCT),'SQL VIA PDS',
//             CLASS=A,
//             MSGCLASS=X,
//             NOTIFY=&SYSUID
//*
//STEP01   EXEC PGM=IKJEFT01,DYNAMNBR=20
//STEPLIB  DD DISP=SHR,DSN=DSN.V13R1M0.SDSNLOAD
//SYSTSPRT DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//SYSUDUMP DD SYSOUT=*
//SYSTSIN  DD *
  DSN SYSTEM(DB9G)
  RUN PROGRAM(DSNTEP2) PLAN(DSNTEP13) -
      LIB('DSN.V13R1M0.RUNLIB.LOAD')
  END
/*
//SYSIN    DD DISP=SHR,DSN=IBMUSER.WORKBOOK.SQL(SELCOPA)
//

Essa estrutura permite usar o mesmo membro:

  • no SPUFI;

  • em batch;

  • em processos automatizados;

  • em pipelines;

  • em testes de implantação.


37. Erros comuns e possíveis soluções

SQLCODE -204

Objeto não encontrado.

Exemplo:

SQLCODE = -204

Possíveis causas:

  • tabela inexistente;

  • schema incorreto;

  • nome não qualificado;

  • ambiente errado.

Solução:

SELECT CREATOR,
       NAME
  FROM SYSIBM.SYSTABLES
 WHERE NAME = 'CLIENTE';

Use o nome qualificado:

SELECT *
  FROM CORP.CLIENTE;

SQLCODE -206

Coluna não encontrada.

Possíveis causas:

  • erro de digitação;

  • coluna pertence a outra tabela;

  • alias incorreto.

Verifique:

SELECT NAME,
       COLNO,
       COLTYPE
  FROM SYSIBM.SYSCOLUMNS
 WHERE TBNAME = 'CLIENTE'
   AND TBCREATOR = 'CORP';

SQLCODE -104

Erro de sintaxe.

Exemplo incorreto:

SELECT NOME
  CLIENTE;

Faltou FROM.

Correto:

SELECT NOME
  FROM CLIENTE;

SQLCODE -551

Usuário sem autorização.

Pode faltar:

  • SELECT;

  • INSERT;

  • UPDATE;

  • DELETE;

  • EXECUTE;

  • uso de package ou plan.

A solução deve ser tratada com o administrador de segurança ou DBA.

SQLCODE -811

Um SELECT INTO retornou mais de uma linha.

No SPUFI isso aparece principalmente em testes de SQL que posteriormente serão usados em COBOL.

A consulta deveria retornar uma linha, mas encontrou várias.

Use filtro mais seletivo ou cursor.

SQLCODE -911

Rollback causado por deadlock ou timeout.

O Db2 desfez a unidade de trabalho.

Possíveis ações:

  • reduzir duração da transação;

  • acessar tabelas em ordem consistente;

  • melhorar índices;

  • revisar isolamento;

  • executar commit mais frequente;

  • investigar concorrência.

SQLCODE -913

Deadlock ou timeout sem rollback automático completo em certos contextos.

Exige análise semelhante ao -911.


38. SPUFI e programas COBOL

O SQL testado no SPUFI pode ser levado para um programa COBOL.

SPUFI:

SELECT FIRSTNME,
       LASTNAME
  FROM DSN8C10.EMP
 WHERE EMPNO = '000010';

COBOL:

       EXEC SQL
            SELECT FIRSTNME,
                   LASTNAME
              INTO :WS-FIRST-NAME,
                   :WS-LAST-NAME
              FROM DSN8C10.EMP
             WHERE EMPNO = :WS-EMPNO
       END-EXEC.

A diferença está nas host variables:

:WS-FIRST-NAME
:WS-LAST-NAME
:WS-EMPNO

O SPUFI ajuda a validar:

  • nomes de tabela;

  • nomes de coluna;

  • joins;

  • filtros;

  • funções;

  • acesso esperado.

Mas ele não substitui os testes dentro do programa COBOL, porque o programa ainda envolve:

  • tipos de dados;

  • variáveis indicadoras;

  • SQLCA;

  • cursores;

  • commit;

  • lógica de tratamento de erro;

  • concorrência;

  • package e bind.


39. Curiosidades e easter eggs

O SPUFI é mais “batch” do que parece

Apesar de ser usado interativamente, sua lógica é baseada em arquivos de entrada e saída.

Ele se parece com uma pequena rotina batch controlada por painéis ISPF.

O dataset é parte da documentação

Como o SQL permanece salvo no PDS, ele pode servir como:

  • evidência de teste;

  • histórico;

  • material de treinamento;

  • script reutilizável;

  • base de automação.

O catálogo é o “Google interno” do Db2

Quando você não sabe se uma tabela existe, qual é a coluna, quem criou um índice ou qual package está ligado, o catálogo geralmente possui a resposta.

IEFBR14 não cria datasets sozinho

O programa é apenas uma moldura. A alocação ocorre pela interpretação do JCL.

Um SELECT também pode causar impacto

Muitos iniciantes acreditam que SELECT é sempre inofensivo.

Não é.

Um SELECT ruim pode:

  • fazer tablespace scan;

  • consumir CPU;

  • ler milhões de páginas;

  • ocupar buffer pools;

  • segurar locks;

  • gerar sort;

  • afetar outros usuários.

Leitura também é trabalho.

WITH UR não é magia de desempenho

Ele reduz locking de leitura, mas não corrige:

  • falta de índice;

  • predicado não indexável;

  • join ruim;

  • cardinalidade incorreta;

  • estatísticas antigas.


40. Checklist do Padawan antes de pressionar Enter

Antes de executar:

1. Estou no SSID correto?
2. O dataset de entrada é o membro correto?
3. O output pode ser sobrescrito?
4. O AUTOCOMMIT está adequado?
5. Existe UPDATE, DELETE ou INSERT?
6. O WHERE foi revisado?
7. Testei o filtro com SELECT?
8. O limite de linhas está razoável?
9. Existe aviso de CCSID?
10. Estou autorizado a executar isso?

Para comandos destrutivos, acrescente:

11. Tenho backup ou possibilidade de rollback?
12. Sei quantas linhas serão afetadas?
13. A unidade de trabalho está controlada?
14. Estou fora do horário crítico?
15. O DBA precisa ser avisado?

Conclusão

O SPUFI é uma das ferramentas mais didáticas do ecossistema Db2 for z/OS.

Na superfície, ele parece apenas uma tela para executar SQL. Em profundidade, porém, ele ensina quase todo o vocabulário operacional do mainframe:

  • datasets de entrada e saída;

  • PDS, PDSE e membros;

  • arquivos sequenciais;

  • DCB;

  • RECFM;

  • LRECL;

  • BLKSIZE;

  • espaço primário e secundário;

  • terminadores SQL;

  • planos;

  • pacotes;

  • isolamento;

  • commit e rollback;

  • CCSID;

  • catálogo;

  • SQLCODE;

  • execução interativa;

  • execução batch por JCL.

Para o programador COBOL Padawan, dominar o SPUFI é aprender a conversar diretamente com o Db2 antes de colocar o SQL dentro de um programa.

É nele que você experimenta.

É nele que você erra com segurança — desde que o AUTOCOMMIT esteja corretamente configurado.

É nele que você descobre que um SQL aparentemente simples pode esconder acesso a milhões de linhas.

E é nele que você começa a enxergar o banco não apenas como um lugar onde os dados vivem, mas como um sistema completo de armazenamento, concorrência, transações, segurança e otimização.

No mundo Bellacosa Mainframe, a tela verde nunca é apenas uma tela verde.

Cada campo é uma porta.

Cada parâmetro conta uma história.

Cada mensagem DSNE é um mestre antigo tentando impedir que o Padawan corrompa caracteres, bloqueie uma tabela ou execute um DELETE sem WHERE.

E cada SQLCODE 0 é o Db2 dizendo:

EXECUÇÃO CONCLUÍDA.

A FORÇA DO SQL ESTÁ COM VOCÊ.

Sem comentários:

Enviar um comentário