Aproveitando a folga que o governo "SPED's" me deu para gozar, brincadeira, tenho serviço que não acaba, estou aproveitando para melhorar meus sistemas. Ontem encontrei um problema que me deixou sem entender e sem confiança nos processos que faço. Em qualquer rotina de casdastro, faço o seguinte procedimento de teste:
1 - Entro no cadastro de TIPO DE DOCUMENTO na minha máquina e seleciono o código do item, logo me aparece a descrição e um menu com as opções: alterar, excluir, próxima, anterior, outros. Fico parado nesta tela, não faço nenhum procedimento.
Dados apresentados na tela do sistema.
Código: 0001
Descrição: Teste de atualizacao
Procedimentos feito no código fonte
DBUSEAREA() -> DBSEEK() -> Criei uma matriz com o conteúdo do registro e apresentei na tela. -> Aguardando próxima passo....
2 - Peço para outro usuário entrar no sistema e fazer o mesmo procedimento, todavia, peço para que ele altere o valor do campo descrição.
Dados apresentados na tela do sistema.
Código: 0001
Descrição: Teste de atualizacao que deve ser visualizado
Procedimentos feito no código fonte
DBUSEAREA() -> DBSEEK() -> Crirei uma matriz com o conteúdo do registro e apresentei na tela. -> Usuário seleciona alterar -> Atualizo a matriz com o conteúdo do registro apresento na tela -> READ -> DBRLOCK() -> DBCOMMIT() -> DBUNLOCK()
- Peço para o mesmo confirmar se está tudo gravado e foi confirmado. Na tentativa de evitar deixa escpacar detalhes, deixei o dbu com o arquivo em questão aberto e confirmei que o registro foi modififado, aconteceu oflush no momento exato da atualização do usuário.
Ainda não satisfeito, peço para outro usuário entrar na mesma opção e me dizer o conteúdo de descrição do item código: 0001, e confirmo que foi atualizado.
3 - Após todas as confirmações, volto para a minha máquina que está com as variáveis com conteúdos antigos, seleciono alterar o item e o programa faz o mesmo processo, atualiza a matriz antes de apresentar e deixar o usuário modificar seus conteúdos e para minha surpreza: O conteúdo não é atualizado, é como se o registro não tivesse sido alterado pelo outro usuário.
- Pensei que pudesse ter algum erro na matriz, crio uma nova matriz e acontece o mesmo erro.
- Apresento o conteúdo do campo na tela e o mesmo erro, ou seja, o campo do arquivo também mostra o conteúdo desatualzado. @ 20,01 say AL_TIPOS->descri; INKEY(0)
- Mudei de matriz para variável, o mesmo erro.
- Fiz o teste na mesma máquina abrindo o programa duas vezes e executando os passos acima e acontece o mesmo erro.
- Antes de declarar a matriz, executei um comando DBCOMMIT(), mesmo sabendo que não é correto e não atualizou o conteúdo. @ 20,01 say AL_TIPOS->descri; INKEY(0)
- Quando executo um get direto no campo, FUNCIONA, o conteúdo apresenta ATUALIZADO!!!!!.
Consegui resolver "parcialmente" o problema, digo parcialmente porque nos cadastros é fácil, agora existem situações bem mais complexas como por exemplo:
Um cliente tem vários caminhos na frota e está fazendo um serviço no veÃculo X com o usuário João e no mesmo momento tem outro veÃculo Y, da mesma frota, fazendo um serviço com o usuário Pedro,vamos considerar que ambos estão na situação acima e acontece que o João termina a venda primeiro, e o limite de compra do cliente é ultrapassado no ato da atualização, no momento da venda do usuário Pedro o sistema deverá alertá-lo quanto a isso. Seguindo o acontecimento acima, isso não ocorrerá causando uma falha crÃtica, visto que o banco de dados já está aberto com o mesmo registro em ambos os caso, ou seja, o arquivo de CLIENTES.
A solução foi usando DBSKIP(0) antes de atualizar a matriz. Claro que isso não vale somente para a matriz, pois o próprio conteúdo campo do banco apresentava desatualizado.
O que pude entender é que o conteúdo do registro após o DBSEEK() fica armazenado na memória na hora de declarar o conteúdo ele pega o que esta na memória. Ratificando, fiz o seguinte teste. Antes de declarar o conteúdo da matriz, enviei novamente um DBSEEK() e o conteúdo do campo é atualizado.
Será muito trabalhoso entrar em todas as rotinas do sistema e antes de pegar qualquer conteúdo dos campos acrescentar um DBSKIP(0). Nunca aprendi que isso fosse necessário!
Amigos, dentro do meu entendimento acredito que isso não possa ocorrer. Talvez seja um BUG no RDD DBFCDX do xHarbour.
Não testei nas versões mais antigas, estou extenuado no momento. :)
Uso xHarbour 1.2.1Intl. (Simplex) (Rev. 9421)
Borland C++ 5.8
RDD DBFCDX
Preciso muito dos colegas para entender estes fatos e me sentir "seguro" novamente com a integridade dos dados do sistema.
Saudações,
Júlio.
Segue abaixo o código do cadastro e rotinas que julgo serem importantes:
#include "INKEY.CH"
#include "CLUBE.CH"
FUNCTION CAD_LINHA(n_cod)
LOCAL Atel:=SAVESCREEN(00,00,24,79)
LOCAL wCadastro:=.F.
if n_cod==NIL
ABREARQ(,"AL_LINHA")
else
if VALTYPE(n_cod)=="L"
KEYBOARD(CHR(18)+CHR(65))
else
KEYBOARD(CHR(13))
endif
endif
do whil .t.
rest screen from aw_tel_master
Wcadastro=.F.
cadastro=.F.
v_cod=IIF(VALTYPE(n_cod)!="C",0,val(n_cod))
MOLDURA(03,02,05,22,.F.,"",.T.)
aCoordenadas := { 07,05,16,76 }
@ 04,03 say "C¢digo = " get v_cod pict'99' VALID( iif(LASTKEY()==13 .and. v_cod=0,VISUALIZA("AL_LINHA", aCoordenadas, {"v_cod","val(codigo)"} ),.T.) )
read
if (LASTKEY()==27)
if n_cod=NIL; ABREARQ(,.F.); endif
RESTSCREEN(00,00,24,79,Atel)
retu
elseif (LASTKEY()==530)
Wcadastro=.T.
elseif (LASTKEY()!=530 .and. v_cod>0)
v_cod=STRZERO(v_cod,2)
end
if !Wcadastro
@ 04,03 say "C¢digo = " get v_cod pict"99"
GetList:={}
end
sele AL_LINHA
DBSETORDER(1)
if (!Wcadastro .and. !DBSEEK(v_cod))
MENSAGEM("C¢digo da linha n„o foi encontrado, Verifique !!!",5)
loop
elseif (!Wcadastro .and. DBSEEK(v_cod))
cadastro=.f.
A:=CRIAVAR()
elseif Wcadastro
IF PERG("Aten‡Æo, deseja incluir dados ? ")="N"
loop
end
A:=NEWVAR()
cadastro=.t.
end
do whil .t.
MOLDURA(06,02,08,65,.F.,"",.T.)
@ 04,03 say "C¢digo = " get A[1] pict'99'
GetList:={}
@ 07,03 say "Descri‡Æo = " get A[2] pict"@!" MSG("Entre com a nome da linha")
if cadastro
read
if PERG("Confirma os dados digitados acima ? ")="N"
exit
end
if UPDATED()
sele AL_LINHA
if Wcadastro
AL_LINHA->(DBSETORDER(1)); AL_LINHA->(DBGOBOTTOM()); A[1]=STRZERO((VAL(AL_LINHA->codigo)+1),2)
ADDREC(10)
DBUNLOCK()
end
if !RECLOCK(10)
exit
end
REPLVAR(A)
DBUNLOCK()
DBCOMMIT()
if Wcadastro
if PERGUNTA("C¢digo da linha ‚: "+A[1]+", Deseja continuar ?") == "N"
EXIT
end
end
end
exit
else
GetList:={}
trab_ckey=NAVEGATE(10,55)
if (trab_ckey='A')
DBSKIP(0) // Consegui resolver usando este comando.
A:=CRIAVAR()
cadastro=.T.
elseif (trab_ckey='E')
if !RECLOCK(10)
MENSAGEM("Registro nÆo liberado para exclusÆo ! ! !",2)
exit
end
DBDELETE()
DBUNLOCK()
exit
elseif (trab_ckey='O')
exit
elseif (trab_ckey="P" .or. trab_ckey="A")
A:=CRIAVAR()
end
end
end
if n_cod!=NIL; exit; endif
end
if n_cod=NIL; ABREARQ(,.F.); endif
retu
FUNCTION CriaVar()
RELEASE aGets
aGets := ARRAY(FCOUNT())
AEVAL(aGets, {|x,nI| aGets[nI] := FIELDGET(nI) })
RETURN aGets[/quote]
[quote]FUNCTION ReplVar(aGets)
AEVAL(aGets, {|x,nI| FIELDPUT(nI,x)})
RETURN NIL
FUNCTION RECLOCK(nRetry)
LOCAL lForever, lRet := .T.
nRetry := IIF(nRetry == NIL, 10, nRetry)
lForever := (nRetry == 0)
WHILE !DBRLOCK()
MENSAGEM("Tentando travar registro", 1)
nRetry--
INKEY(1/10)
ENDDO
RETURN lRet