Business - Automação Comercial
Bematech: Trabalhando com Banco de Dados no SB-2030E
Neste artigo, iremos trabalhar com um dos recursos mais importantes do micro-terminal SB-2030E - o Banco de Dados.
por André Luiz R. MunhozNeste artigo, iremos trabalhar com um dos recursos mais importantes do micro-terminal SB-2030E - o Banco de Dados.
Lembrete: Caso você ainda não baixou o VisualSDK Builder, acesse:
http://www.bematech.com.br/suporte/downloads/cpus_win/SDKbuilder.zip (+/- 20MB)
- Conceito
O SB-2030E possui uma área de memória não volátil e protegida, usada exclusivamente para armazenamento de dados. Esta área pode possuir o tamanho de 512KB (modelo SB-2030E) até 2MB (modelo SB-2030EP).
O conceito de banco de dados no SB-2030E é o mesmo conceito que já conhecemos (Campos -> Registros -> Tabelas), com alguns detalhes que veremos a seguir:
a) ao criarmos uma tabela no SB-2030E, devemos determinar inicialmente o tamanho máximo de registros que esta tabela comportará;
b) a tabela depois de criada ou em uso, não poderá ser removida ou ter seu tamanho modificado e;
c) é possível criar até 128 tabelas no SB-2030E.
Usaremos estruturas para a criação de tabelas dentro do SB-2030E. Veja um exemplo:
/*
A estrutura Produto receberá registros formados pelos campos:
Codigo tipo char com 14 posições;
Descricao tipo char com 30 posições;
Aliquota tipo char com 3 posições e;
VlrUnitario tipo long.
que serão armazenados na tabela TblPro.
*/
struct Produto
{
char Codigo [ 14 ];
char Descricao [ 30 ];
char Aliquota [ 3 ];
long VlrUnitario;
};
.
.
.
Para que possamos definir o tipo (char, int, long e etc) e o tamanho de cada
campo que a tabela conterá, precisamos usar uma formatação própria, da seguinte
forma:
"XyXy"
onde:
"X" corresponde a primeira letra do tipo do campo (variável) em maiúscula
(Char, Int, Long e etc) e;
"y" corresponde ao tamanho da área desejada.
Para entendermos melhor esta definição, vamos tomar como exemplo a estrutura Produto
acima citada, onde temos 4 campos (variáveis), 3 são do tipo char e 1 do
tipo long.
O formato de nossa tabela seria assim:
"C14C30C3L", 1000
onde:
C14 = char de 14 posições, usado para representar o primeiro campo "Codigo";
C30 = char de 30 posições, usado para representar o segundo campo "Descricao";
C3 = char de 3 posições, usado para representar o terceiro campo "Aliquota";
L= long, usado para representar o quarto campo "VlrUnitario" e;
1000 = quantidade de registros que a tabela armazenará.
Obs: Variáveis do tipo char são as únicas que usam definição de tamanho.
Vamos conhecer agora, as principais funções de acesso ao banco de dados que iremos
usar em nosso exemplo.
- função formataSDK
A função formataSDK formata a memória não volátil destinada ao armazenamento dos
dados, preparando-a para receber as tabelas e seus registros. Ao executarmos esta
função, todas as tabelas existentes e seus registros serão apagados. Então, teremos
que preparar uma rotina que verifique se a memória já está formatada, para que este
processo não seja realizado toda vez que iniciar o sistema.
- função criatabelaSDK
A função criatabelaSDK cria uma tabela na memória não volátil, com um tamanho máximo
que especificamos. Se a criação for bem sucedida, a tabela iniciará com 0 (zero)
byte gravado. Caso a tabela já exista, receberemos um código de erro como retorno
que poderemos tratar. Para que possamos criar as tabelas, a formatação da memória
deve ter sido feita anteriormente.
- função addregistroSDK
A função addregistroSDK adiciona um novo registro ao final da tabela. Esta inclusão
sempre será feita após o último registro existente na tabela. Caso for desejado,
podemos exigir que o ponteiro da tabela fique posicionado sobre o novo registro
incluído. Isso é configurado via parâmetro na função.
- função seekregistroSDK
A função seekregistroSDK posiciona o ponteiro da tabela sobre um determinado registro,
utilizando um campo e uma condição definida, para localizá-lo. Se a pesquisa for
bem sucedida, os campos contidos no registro localizado serão colocados na estrutura
(struct) criada para a tabela. O campo usado para a pesquisa, poderá possuir um
valor numérico (int) ou um texto (char). O início da pesquisa será determinado por
um dos parâmetros da função e poderá ser realizada a partir do primeiro registro
da tabela (após o BOF) ou a partir da posição atual. Para ambos os casos, a pesquisa
só termina após encontrar o primeiro registro que satisfaça a condição imposta ou
até atingir o fim da tabela (EOF). Ao localizar o registro, a tabela será posicionada,
caso contrário o posicionamento atual não será afetado.
- função deleteregistroSDK
A função deleteregistroSDK apaga somente um determinado registro da tabela. Para
isso, devemos primeiro posicionar o ponteiro da tabela sobre o registro que será
excluído. Caso o ponteiro da tabela esteja posicionado sobre o <BOF> ou <EOF>,
um código de retorno será enviado à função. Após a exclusão do registro, o ponteiro
da tabela fica posicionado sobre o próximo registro, e se o registro deletado for
o último, o ponteiro fica posicionado sobre o <EOF>.
- função positionregistroSDK
A função positionregistroSDK posiciona o ponteiro da tabela sobre um registro desejado.
O ponteiro pode ser posicionado sobre qualquer registro compreendido entre <BOF>
e <EOF>, mesmo que o registro esteja deletado. Esta função posiciona o ponteiro
da tabela no registro para poder executar operações de escrita, consulta e exclusão.
Se o número do registro a ser posicionado for maior que a quantidade total de registros
da tabela, o ponteiro será posicionado sobre o <EOF>.
- função readregistroSDK
A função readregistroSDK lê um registro da tabela e coloca na estrutura (struct)
criada para a tabela ou em uma nova estrutura, desde que possua os mesmos campos.
Se o ponteiro da tabela estiver posicionado sobre o <BOF> ou <EOF> um
código de retorno será enviado à função.
- função writeregistroSDK
A função writeregistroSDK escreve sobre um determinado registro eliminando o conteúdo
anterior. Se o ponteiro da tabela estiver posicionado sobre o <BOF> ou <EOF>,
um código de retorno será enviado à função.
- função zeratabelaSDK
A função zeratabelaSDK apaga todo o conteúdo da tabela especificada.
- função lestatustabelaSDK
A função lestatustabelaSDK retorna informações da tabela especificada, como:
Quantidade total de registros da tabela;
Quantidade de registros gravados na tabela;
Tamanho em bytes do registro e etc.
- Criando um projeto com banco de dados
Vamos iniciar um novo projeto no VisualSDK Builder (menu "File" - opção "New Project")
para praticar as funções relacionadas ao banco de dados.
Obs: Não esqueça de configurar o ambiente para o modelo SB-2030E antes de compilar
o projeto, e localizar o micro-terminal na rede antes de transferir a aplicação
(menu "Project" - opção "Options" ).
O primeiro passo é criarmos a estrutura que estará recebendo os dados para posteriormente
serem armazenados no banco. Para isso, abaixo das linhas de #include, insira
a struct Produto da seguinte forma:
struct Produto
{
char Codigo [ 14 ];
char Descricao [ 30 ];
char Aliquota [ 3 ];
long VlrUnitario;
};
Ela será global e guardará informações sobre o código, descrição, alíquota e valor
unitário de nosso produto.
Dentro do main(), vamos criar algumas variáveis que serão usadas no código
e referenciar a struct.
void far main()
{
int iOpcao,
iResp,
iRet;
char cTempVlrUnitario[ 9 ];
struct Produto CampoProduto;
.
.
.
Criamos um menu de rolagem para executar as funções separadamente, assim poderemos
entender melhor o funcionamento de cada uma e usá-las em nossos projetos futuros.
As opções de nosso menu de rolagem são: "Formata Memoria BD", "Cria Tabela", "Insere
Registro", "Pesquisa Registro", "Apaga Registro" e "Status Tabela".
O código para a criação deste menu fica assim:
.
.
.
clrscrU();
getopcao( &iOpcao, 0, "<- Formata Memoria BD ->,<- Cria
Tabela ->,<- Insere Registro ->,<- Pesquisa Registro ->,<- Apaga
Registro ->,<- Status Tabela ->" );
.
.
.
Iremos tratar a escolha das opções dentro de um "switch/case", sendo que
o "case 0" corresponde à opção "Formata Memoria BD", conforme abaixo:
.
.
.
switch( iOpcao )
{
case 0:
clrscrU();
printfU( "AVISO: Os dados serao apagados.\n" );
printfU( "Deseja continuar ?: " );
getopcao( &iResp, 0, "<- NAO ->,<-
SIM ->" );
if ( iResp == 1 )
{
clrscrU();
centralizaU( 1, "<<< Formatando,
aguarde... >>>" );
espera0( 1000 );
if ( ( formatSDK( 524288 ) ) != 0 )
{
clrscrU();
centralizaU( 1, "<<<
PROBLEMAS NA FORMATACAO >>>" );
centralizaU( 2, "Pressione
algo, p/ continuar..." );
getch();
}
else
{
clrscrU();
centralizaU( 1, "<<<
FORMATACAO CONCLUIDA COM SUCESSO >>>" );
centralizaU( 2, "Pressione
algo, p/ continuar..." );
getch();
}
}
break;
.
.
.
Repare que neste código, fazemos uma pergunta ao operador antes de iniciar a formatação
da memória reservada ao banco de dados e testamos o retorno da função "formataSDK".
Caso o retorno seja 0 (zero) significa que a formatação foi bem sucedida e exibimos
uma mensagem de OK, caso contrário exibimos uma outra mensagem para o operador.
O tamanho da memória neste exemplo, é de 512KB representados em bytes (524288 bytes).
Caso o micro-terminal seja o modelo SB-2030EP, temos um pente de expansão de 2MB
para o banco de dados, então este deverá ser formatado no tamanho de 2097152 bytes.
O "case 1" corresponde à função "Cria Tabela":
.
.
.
case 1:
iRet = criatabelaSDK( "TblPro", "C14C30C3L", 1000
);
clrscrU();
switch( iRet )
{
case 1:
centralizaU( 1, "<<<
TABELA JA EXISTE ! >>>" );
espera0( 2 SEGUNDOS );
break;
case 2:
centralizaU( 1, "<<<
NOME TABELA ACIMA DE 6 CARACTERES ! >>>" );
espera0( 2 SEGUNDOS );
break;
case 3:
centralizaU( 1, "<<<
QTDE MAX DE TABELAS ATINGIDA ! >>>" );
espera0( 2 SEGUNDOS );
break;
case 4:
centralizaU( 1, "<<<
ERRO NA DECLARACAO DA STRUCT ! >>>" );
espera0( 2 SEGUNDOS );
break;
case 5:
centralizaU( 1, "<<<
STRUCT ACIMA DE 100 CARACTERES ! >>>" );
espera0( 2 SEGUNDOS );
break;
case 6:
centralizaU( 1, "<<<
QTDE REGISTROS ACIMA DA ESPECIFICADA ! >>>" );
espera0( 2 SEGUNDOS );
break;
case 7:
centralizaU( 1, "<<<
MEMORIA NAO FORMATADA ! >>>" );
espera0( 2 SEGUNDOS );
break;
default:
centralizaU( 1, "<<<
TABELA CRIADA COM SUCESSO ! >>>" );
espera0( 2 SEGUNDOS );
break;
}
break;
.
.
.
Na função criatabelaSDK estamos passando como parâmetros: o nome da tabela
(TblPro), seu formato (C14C30C3I) e seu tamanho total de registros
(1000). Estamos também analisando o retorno desta função, exibindo uma mensagem
para cada situação ao operador.
No "case 2" adicionamos um registro à tabela "TblProd":
.
.
.
case 2:
memset( CampoProduto.Codigo, NULL,
sizeof( CampoProduto.Codigo ) );
memset( CampoProduto.Descricao, NULL,
sizeof( CampoProduto.Descricao ) );
memset( CampoProduto.Aliquota, NULL,
sizeof( CampoProduto.Aliquota ) );
memset( cTempVlrUnitario, NULL, sizeof( cTempVlrUnitario ) );
CampoProduto.VlrUnitario = 0;
clrscrU();
setcursorU( ON );
printfU( "Codigo: " );
getstring( CampoProduto.Codigo, 13, NUMERICO,
NULL, NULL );
if ( ( seekregistroSDK( "TblPro", (char*)&CampoProduto,
(char*)&CampoProduto.Codigo, "=", "F" ) ) != 0 )
{
clrscrU();
printfU( "Descricao......: "
);
getstring( CampoProduto.Descricao, 29, ALFA, NULL,
NULL );
printfU( "\nCodigo Aliquota:
" );
getstring( CampoProduto.Aliquota, 2, ALFA, NULL,
NULL );
clrscrU();
printfU( "Valor Unitario:
" );
getstring( cTempVlrUnitario,
8, FORMAT | REVERSO, " . , ", NULL );
setcursorU( OFF );
CampoProduto.VlrUnitario = atol(
cTempVlrUnitario );
if ( ( addregistroSDK( "TblPro", (char*)&CampoProduto, 0 ) ) == 0 )
{
clrscrU();
setcursorU(
OFF );
centralizaU(
1, "<< Produto cadastrado com sucesso ! >>" );
espera0(
2 SEGUNDOS );
}
else
{
clrscrU();
setcursorU( OFF );
centralizaU(
1, "<< Problemas com o cadastro ! >>" );
espera0( 2 SEGUNDOS );
}
}
else
{
clrscrU();
setcursorU( OFF );
centralizaU( 1, "<< Produto
ja cadastrado ! >>" );
espera0( 2 SEGUNDOS );
}
break;
.
.
.
Neste case, inicializamos as variáveis da struct em memória com NULL
(\0) e fazemos a primeira entrada de dados, através do código do produto (função
getstring). Repare que antes de entrar com as outras informações do produto,
fazemos uma pesquisa na tabela para verificar se o código do produto informado já
está cadastrado (função seekregistroSDK). Caso o retorno seja diferente de
0 (zero), entramos com as demais informações (descrição, alíquota e valor unitário),
caso contrário exibimos uma mensagem ao operador informando que o produto já se
encontrada cadastrado na tabela, evitando que o mesmo seja duplicado. Esta é uma
operação normal quando se trabalha com banco de dados!
Fazemos a pesquisa do produto cadastrado, no case 3:
.
.
.
case 3:
memset( CampoProduto.Codigo, NULL, sizeof( CampoProduto.Codigo
) );
clrscrU();
setcursorU( ON );
printfU( "Codigo: " );
getstring( CampoProduto.Codigo,
13, NUMERICO, NULL, NULL );
setcursorU( OFF );
if ( ( seekregistroSDK( "TblPro",
(char*)&CampoProduto, (char*)&CampoProduto.Codigo, "=", "F" ) ) == 0 )
{
clrscrU();
printfU( "Descricao......: %s\n",
CampoProduto.Descricao );
printfU( "Codigo Aliquota: %s
", CampoProduto.Aliquota );
printfU( "Valor: %l", CampoProduto.VlrUnitario
);
getch();
}
else
{
clrscrU();
setcursorU( OFF );
centralizaU( 1, "<< Produto
nao cadastrado ! >>" );
espera0( 2 SEGUNDOS );
}
break;
.
.
.
Esta rotina é bem simples! Inicializamos a variável CampoProduto.Codigo e
fazemos a entrada do código do produto. Através da função seekregistroSDK
(vista anteriormente), fazermos a busca deste código na tabela. Se o código for
encontrado, exibimos a decrição, o código da alíquota e o valor unitário do produto,
caso contrário exibimos uma mensagem para o operador.
No case 4, excluímos o produto:
.
.
.
case 4:
memset( CampoProduto.Codigo, NULL, sizeof( CampoProduto.Codigo
) );
clrscrU();
setcursorU( ON );
printfU( "Codigo: " );
getstring( CampoProduto.Codigo, 13, NUMERICO,
NULL, NULL );
setcursorU( OFF );
if ( ( seekregistroSDK( "TblPro", (char*)&CampoProduto,
(char*)&CampoProduto.Codigo, "=", "F" ) ) == 0 )
{
clrscrU();
iRet = deleteregistroSDK( "TblPro" );
switch( iRet )
{
case 1:
centralizaU( 1, "<<
ERRO: Tabela inexistente ! >>" );
espera0( 2 SEGUNDOS
);
break;
case 2:
centralizaU( 1, "<<
ERRO: Encontrado <BOF> ! >>" );
espera0( 2 SEGUNDOS
);
break;
case 3:
centralizaU( 1, "<<
ERRO: Encontrado <EOF> ! >>" );
espera0( 2 SEGUNDOS
);
break;
case 4:
centralizaU( 1, "<<
AVISO: Produto ja excluido ! >>" );
espera0( 2 SEGUNDOS
);
break;
default:
centralizaU( 1, "<<
Registro excluido com sucesso ! >>" );
espera0( 2 SEGUNDOS
);
break;
}
}
else
{
clrscrU();
setcursorU( OFF );
centralizaU( 1, "<< Produto nao
cadastrado ! >>" );
espera0( 2 SEGUNDOS );
}
break;
.
.
.
Semelhante ao case 3, neste case fazemos a pesquisa do produto no
banco de dados e caso seja encontrado, fazemos sua deleção (função deleteregistroSDK).
É feito um tratamento de retorno para a função deleteregistroSDK exibindo
mensagens para o operador.
E, no case 5 exibimos algumas informações do estado atual da tabela:
.
.
.
case 5:
if ( ( lestatustabelaSDK( "TblPro" ) ) == 0 )
{
clrscrU();
printfU( "Tamanho da Tabela: %l registro(s)",
SDK_STATUS.QtdeTotalRegistros );
espera0( 2 SEGUNDOS );
clrscrU();
printfU( "Registros Gravados: %l registro(s)",
SDK_STATUS.QtdeRegistrosGravados );
espera0( 2 SEGUNDOS );
}
else
{
clrscrU();
centralizaU( 1, "<<< TABELA INEXISTENTE
>>>" );
espera0( 2 SEGUNDOS );
}
break;
}
} /* Fim do programa */
Aqui, apenas verificamos algumas situações, através da função lestatustabelaSDK,
retornadas por constantes do banco de dados, como quantidade total de registros
e o número de registros cadastrados na tabela.
- DarumaFramework.SO no LinuxAutomação Comercial
- Palavra de status da impressora na DarumaFrameworkAutomação Comercial
- TEF – Comprovante de Crédito ou DébitoAutomação Comercial
- Comunicar com equipamentos Daruma em linguagens 16bits e DOSAutomação Comercial
- Verificando Redução Z nas Impressoras DarumaAutomação Comercial