Os famosos campos COMP-3

Muitos desenvolvedores que não trabalham diretamente com COBOL algumas vezes já se deparam com arquivos que contêm esse tipo de campo. Neste artigo você vai conhecer sua estrutura, para que ele serve e como ele pode ser lido por outras linguagens que não reconhecem dados desse tipo.

PICTURES e USAGES

A rigor, o COBOL só possui três tipos de dados:

TipoPictureExemplo de Variável
AlfabéticoA03 NOME PIC A(030) VALUE SPACES.
Numérico903 MATRICULA PIC 9(006) VALUE ZEROS.
AlfanuméricoX03 ENDERECO PIC X(030) VALUE SPACES.

Na prática, utilizamos quase sempre as pictures 9 e X, uma vez que campos alfanuméricos podem ser preenchidos com letras ou números e isso não acrescenta nenhum “custo” sob o ponto de vista prático.

Se a cláusula PICTURE indica o tipo e o tamanho de uma variável, por outro lado podemos dizer que a cláusula USAGE informa ao compilador a finalidade dessa variável, consequentemente influenciando a forma como o programa vai tratá-la. Em outras palavras, o uso correto da cláusula USAGE pode tornar o programa mais eficiente.

Normalmente a cláusula USAGE está associada a um item elementar, como no exemplo abaixo:

03 WT-AC-VENDAS PIC S9(013)V9(002) VALUE ZEROS USAGE IS PACKED-DECIMAL.

Mas podemos também associá-la a um item de grupo. Nesse caso, todos os seus itens elementares passam a ter o mesmo “uso”:

01 WT-CONTADORES USAGE IS BINARY.
   03 WT-CT-VENDAS     PIC S9(007) VALUE ZEROS.
   03 WT-CT-COMPRAS    PIC S9(007) VALUE ZEROS.

As palavras USAGE e IS são opcionais e por isso frequentemente são omitidas, como no exemplo abaixo:

03 WT-AC-VENDAS PIC S9(013)V9(002) VALUE ZEROS PACKED-DECIMAL.

A opção mais comum para a cláusula USAGE é a USAGE DISPLAY, que por ser default não precisa ser declarada junto com as variáveis. As variáveis abaixo são exemplos de variáveis USAGE DISPLAY:

01 WT-CONTADORES.
    03 WT-CT-LIDOS    PIC 9(005) VALUE ZEROS USAGE DISPLAY.
    03 WT-CT-GRAVADOS PIC 9(005) VALUE ZEROS USAGE DISPLAY.

E por DISPLAY ser o USAGE default, normalmente as declaramos assim:

01 WT-CONTADORES.
    03 WT-CT-LIDOS    PIC 9(005) VALUE ZEROS.
    03 WT-CT-GRAVADOS PIC 9(005) VALUE ZEROS.

A característica principal dos campos USAGE DISPLAY é que cada caracter ocupa um byte de memória, que é representado por seu próprio código ASCII ou EBCDIC, dependendo do equipamento. Um contador numérico, USAGE DISPLAY, com tamanho cinco ocupará exatamente cinco bytes de memória:

Cobol: Posicionamento em memória de um campo USAGE DISPLAY
Figura 68. Posicionamento em memória de um campo USAGE DISPLAY

Esse é o formato ideal quando precisamos exibir o valor do campo em telas ou relatórios; ou quando precisamos enviar a informação para outros sistemas (em outras plataformas) que podem não ler corretamente outros tipos de dados que são específicos do COBOL.

Agora que entendemos o USAGE default, será mais fácil entender o USAGE COMP-3.

USAGE PACKED-DECIMAL, mais conhecido como COMP-3

Variáveis COMP-3 (ou PACKED DECIMAL ou decimal compactada) possuem dois dígitos armazenados num mesmo byte de memória, com exceção do byte mais à direita, que terá um dígito e um sinal positivo ou negativo.

Tradicionalmente elas são declaradas da seguinte maneira:

01 WT-CONTADORES.
    03 WT-CT-LIDOS     PIC S9(005) VALUE ZEROS USAGE COMP-3.
    03 WT-CT-GRAVADOS  PIC S9(006) VALUE ZEROS USAGE COMP-3.

Mas em compiladores que adotaram o padrão COBOL ISO 2002 elas também podem ser declaradas como se vê nos exemplos abaixo. As duas formas produzem o mesmo resultado:

01 WT-CONTADORES.
    03 WT-CT-LIDOS     PIC S9(005) VALUE ZEROS USAGE PACKED-DECIMAL.
    03 WT-CT-GRAVADOS  PIC S9(006) VALUE ZEROS USAGE PACKED-DECIMAL.

Imagine agora que a variável WT-CT-LIDOS recebeu o conteúdo +01932. Em memória ela seria representada assim:

Cobol: Posicionamento em memória de um campo decimal compactado
Figura 69. Posicionamento em memória de um campo decimal compactado com sinal positivo

Para colocar dois caracteres num único byte, o COBOL utiliza os quatro primeiros bits (primeiro nible) para um caracter e os quatro bits seguintes (segundo nible) para o outro caracter. O primeiro efeito, óbvio, é que conseguimos economizar praticamente metade do espaço em memória.

Os números binários agora correspondem a hexadecimais diferentes, que podem ou não ter representação gráfica. Na figura anterior, o símbolo “?” indica que o hexadecimal resultante não tem representação gráfica na tabela ASCII. É por isso que quando usamos um editor de texto puro para abrir um arquivo com campos decimais compactados não conseguimos ver seu conteúdo. Alguns editores possuem recursos para mostrar o hexadecimal correspondente a cada byte, e só usando esses recursos podemos ver e/ou editar o conteúdo desse tipo de campo.

Na maioria das plataformas, o desempenho de operações aritméticas e comparações entre campos numéricos decimais compactados é superior quando comparado aos campos numéricos USAGE DISPLAY. A contrapartida é que poucas linguagens de programação sabem interpretar os campos PACKED-DECIMAL criados pelo COBOL. Essa é uma das razões pelas quais evitamos usar esse tipo de formato de campo em arquivos que serão exportados para sistemas de outras plataformas.

Outro ponto que vale a pena destacar é que um campo decimal compactado sempre ocupará uma quantidade ímpar de bytes de memória: um campo 9(005) ou S9(005) ocupará 3 bytes, porque metade do byte mais à direita será reservado para o sinal mesmo que esse sinal não tenha sido declarado explicitamente na picture.

Consequentemente, campos decimais compactados de tamanhos pares – S9(008), S9(010) , S9(008)V9(002) – sempre desperdiçam metade do byte mais à esquerda. Observe na figura abaixo o posicionamento em memória de uma variável PIC 9(006) PACKED-DECIMAL preenchida com o valor 001932:

Cobol: Campo decimal compactado com tamanho par
Figura 70. Posicionamento em memória de campo decimal compactado com tamanho par

Repare que o programa teve que completar metade do byte mais à esquerda com zero binário. O espaço de memória é o mesmo que seria ocupado por uma variável S9(007). Esse é um dos motivos pelos quais recomenda-se que toda variável decimal compactada tenha tamanho ímpar e uma declaração explícita de sinal. Mas além disso, essa prática favorece o desempenho do programa, ainda que hoje em dia qualquer diferença só seja percebida em programas que processam grandes volumes de dados, na ordem de dezenas de milhões de registros ou mais.

O tamanho máximo de um campo decimal compactado é de 31 dígitos, contando a parte inteira e a decimal, se houver. Assim, PIC S9(029)V9(002) PACKED-DECIMAL é um tamanho válido, pois o sinal e a vírgula não ocupam espaços.

Como ler esse campo em outras plataformas

O ideal é que arquivos gerados pelo COBOL com destino a outras plataformas e linguagens sejam formados apenas por campos USAGE DISPLAY.

Esse cuidado facilita a integração entre sistemas de diferentes linguagens, além de evitar possíveis problemas de conversão quando a origem do arquivo for uma plataforma EBCDIC (basicamente mainframes) e o destino for uma plataforma ASCII (Windows ou Linux, por exemplo).

Quando isso não é possível, a solução mais simples é codificar um programa adicional muito simples na plataforma de origem (em COBOL) para gerar um novo arquivo com os campos descompactados.

Mas existem situações em que nem isso é possível. Nesses casos, existem algumas soluções open source, como o JRecord e RecordEditor, que prometem fazer a conversão tanto de qualquer formato de campo gerado em plataforma mainframe, inclusive comp-3.

Se você, como eu, gosta de construir sua própria solução para não depender da solução de terceiros, dá uma olhada nesse laboratório que fiz aqui para construir uma solução Java que traduza campos comp-3.

Você também pode ler mais sobre USAGE (e outros conceitos do COBOL) que estão disponíveis no livro COBOL: Do Básico ao Avançado, que está liberado para leitura aqui nesse portal.


Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *