Hoje vou mostrar como solucionar o erro Update error – lock required em suas customizações.
Recentemente um aluno me perguntou, que em uma das customizações que ele tinha, ocorria esse erro de Update error – lock required, e ele esta essencialmente relacionado quando você “desposiciona” uma tabela no meio do RecLock.
Como assim Daniel? Imagina o seguinte cenário, você deu um comando para incluir um registro ou alterar, via RecLock, vamos usar como exemplo, a tabela ZD1.
Nesse contexto, o Protheus por trás, preparou tudo que era necessário para você fazer a atualização dessa tabela. Mas e se no meio dessa atualização, você deu um DbSkip, um DbCloseArea, um DbGoTop, etc… qualquer comando que faça a tabela ZD1 ir para outro registro e sair do atual, o que irá acontecer?
Ele irá gerar esse erro, e não irá concluir o RecLock. Por exemplo, abaixo um trecho que ocasiona esse problema:
//Bibliotecas
#Include "TOTVS.ch"
#Include "TopConn.ch"
/*/{Protheus.doc} User Function zTstLock
Função que demonstra que não devemos desposicionar uma tabela ao dar um RecLock
@type Function
@author Atilio
@since 13/07/2021
/*/
User Function zTstLock()
Local aArea := GetArea()
//Inclui o registro
RecLock("ZD1", .T.)
ZD1->ZD1_FILIAL := FWxFilial('ZD1')
ZD1->ZD1_CODIGO := fUltCod()
ZD1->ZD1_NOME := "Novo Artista"
ZD1->(MsUnlock())
RestArea(aArea)
Return
Static Function fUltCod()
Local cUltimo := ""
DbSelectArea("ZD1")
ZD1->(DbGoBottom())
cUltimo := Soma1(ZD1->ZD1_CODIGO)
Return cUltimo
Notou algo estranho? Veja que existe uma função para buscar o último registro da tabela, e nela esta dando um DbGoBottom, durante o Lock, então encontramos o problema.
Qual seria e melhor solução então? O que eu recomendo para meus alunos, é colocar os valores do Lock em variáveis, antes de iniciar o RecLock, e como podemos ter filiais diferentes, para buscar o código, podemos optar por uma query SQL ou pela função GetSXENum.
Abaixo então, como ficou a função após os ajustes:
//Bibliotecas
#Include "TOTVS.ch"
#Include "TopConn.ch"
/*/{Protheus.doc} User Function zTstLock
Função que demonstra que não devemos desposicionar uma tabela ao dar um RecLock
@type Function
@author Atilio
@since 13/07/2021
/*/
User Function zTstLock()
Local aArea := GetArea()
Local cZD1Filial := FWxFilial('ZD1')
Local cCodigo := fUltCod()
Local cNome := "Novo Artista"
//Inclui o registro
RecLock("ZD1", .T.)
ZD1->ZD1_FILIAL := cZD1Filial
ZD1->ZD1_CODIGO := cCodigo
ZD1->ZD1_NOME := cNome
ZD1->(MsUnlock())
RestArea(aArea)
Return
Static Function fUltCod()
Local aArea := GetArea()
Local cUltimo := StrTran(Space(TamSX3('ZD1_CODIGO')[1]), ' ', '0')
Local cQuery := ""
//Busca o último registro
cQuery += " SELECT " + CRLF
cQuery += " ISNULL(MAX(ZD1_CODIGO), '" + cUltimo + "') AS ULTIMO " + CRLF
cQuery += " FROM " + CRLF
cQuery += " " + RetSQLName('ZD1') + " ZD1 " + CRLF
cQuery += " WHERE " + CRLF
cQuery += " ZD1_FILIAL = '" + FWxFilial('ZD1') + "' " + CRLF
TCQuery cQuery New Alias "QRY_ULT"
//Incrementa 1 no último
cUltimo := Soma1(QRY_ULT->ULTIMO)
QRY_ULT->(DbCloseArea())
RestArea(aArea)
Return cUltimo
Bom pessoal, por hoje é só.
Abraços e até a próxima.