Jamais desposicione uma tabela ao dar um Lock

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.

Dan Atilio (Daniel Atilio)
Especialista em Engenharia de Software pela FIB. Entusiasta de soluções Open Source. E blogueiro nas horas vagas.

Deixe uma resposta