Clipper On Line • Ver Tópico - Erro em acesso ao banco de dados com internet lenta
Página 1 de 3

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 25 Jul 2014 01:00
por cjp
Colegas,

Estou viajando (no Chile), acessando à internet pelo wi-fi do hotel, que é muito, mas muito ruim. Em razão disso, estou tendo bastante dificuldade de acesso ao banco de dados MySQL em meu provedor. Até aí tudo normal.

O problema é que, quando a internet cai, dá erro no programa:

Ocorreu o erro: Error SDDODBC/1903  08S01 [MySQL][ODBC 3.51 Driver][mysqld-5.6.10-log]Lost connection to MySQL server during query: 


Também dá pra entender que se perca a conexão ao banco de dados quando a internet cai, obviamente.

Minha dúvida é: será que não tem como evitar que dê erro no programa por isso? A conexão poderia resultar .f., mas não precisaria dar erro no programa.

Minha função está assim:

if conexsql()=.f.
            Return .f.
    endif
         DBUSEAREA( .T.,, "SELECT * FROM recado WHERE visto='S' OR (usuario='I' AND visto='N') LIMIT 10", "recado" )
         ...

function conexsql
         LOCAL nConnection, disconnection
       local nvz :=0
         RDDSETDEFAULT( "SQLMIX" )
         nConnection := RDDINFO( 1001, { "ODBC", "Server=mysql.xxx.com.br;Driver={MySQL ODBC 3.51 Driver};dsn=;User=xxx;pwd=xxx;database=xxx;" } )
       do while .t.
            IF nConnection == 0
            nvz++
            if nvz>1
               @ maxrow()-1,1 clear to maxrow()-1,maxcol()-1
               @ maxrow()-1,1 say "Tentando conexão com o servidor; aguarde..."
            endif
            inkey(nvz*2)
            if nvz>3 .or. (nvz>0 .and. nrtsql>0 .and. ("TAREFAS"$upper(Hb_CmdArgArgV()) .or. "AGENDA"$upper(Hb_CmdArgArgV())))
                  RDDSETDEFAULT( "DBFNTX" )
              nrtsql++
                  Return .f.
            endif
         else
            exit
         endif
       enddo
return .t.


Tudo que eu preciso é evitar que o programa dê erro. Se não funcionar a conexão, não tem problema.

Outro problema que estou tendo pelo mesmo motivo é que, frequentemente, o programa trava na conexão ao banco de dados. Não retorna .f., mas também não avança. Fica infinitamente travado.

Alguém me ajudaria?

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 30 Jul 2014 08:45
por Toledo
cjp escreveu:O problema é que, quando a internet cai, dá erro no programa

Bom, se este erro for dentro da função DBUSEAREA(), não sei dizer se existe alguma maneira de evitar a apresentação da mensagem de erro, pois será um erro interno da função.
Uma saída seria verificar se tem conexão com a Internet antes de usar a função onde está ocorrendo o erro, usar por exemplo está função:

Function IsConnected()
local nFlags := 0, lRet := .f.
if CallDll32( "InternetGetConnectedState", "WININET.DLL", @nFlags, 0 ) == 1
  if CallDll32( "InternetCheckConnection", "WININET.DLL", "http://www.google.com",1,0) == 1
    lRet := .t.
  endif
endif
RETURN lRet


cjp escreveu:Outro problema que estou tendo pelo mesmo motivo é que, frequentemente, o programa trava na conexão ao banco de dados. Não retorna .f., mas também não avança. Fica infinitamente travado.

Observando o seu código postado na mensagem anterior, notei que você criou uma função (conexsql()) para fazer a conexão.
function conexsql
  LOCAL nConnection, disconnection
  local nvz :=0
  RDDSETDEFAULT( "SQLMIX" )
  nConnection := RDDINFO( 1001, { "ODBC", "Server=mysql.xxx.com.br;Driver={MySQL ODBC 3.51 Driver};dsn=;User=xxx;pwd=xxx;database=xxx;" } )
  do while .t.
    IF nConnection == 0
      nvz++
      if nvz>1
        @ maxrow()-1,1 clear to maxrow()-1,maxcol()-1
        @ maxrow()-1,1 say "Tentando conexão com o servidor; aguarde..."
      endif
      inkey(nvz*2)
      if nvz>3 .or. (nvz>0 .and. nrtsql>0 .and. ("TAREFAS"$upper(Hb_CmdArgArgV()) .or. "AGENDA"$upper(Hb_CmdArgArgV())))
        RDDSETDEFAULT( "DBFNTX" )
        nrtsql++
        Return .f.
      endif
    else
      exit
    endif
  enddo
return .t.

Na linha 5, você está tentando fazer a conexão com o banco de dados, que retorna um valor para nConnection. Depois na linha 6 você abre um Do While e fica num Loop verificando o valor da nConnection, só que em nenhum lugar dentro do Do While você tenta fazer novamente a conexão com o banco de dados, neste caso nConnection nunca vai mudar o seu valor e por este motivo que você está achando que "Fica infinitamente travado".

Abraços,

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 30 Jul 2014 12:00
por cjp
Realmente estava errada a função conexsql(), já corrigi.

Agora o outro problema é sim na dbusearea(). Quando não tem internet não tem problema, porque a conexsql() já retorna .f. e ele nem tenta a dbusearea(). O problema é quando a internet está ruim. Daí, ocorre de a conexsql() retornar .t. e a internet cair logo em seguida. Testar a internet antes da dbusearea() não resolveria, pois a conexsql() já testou e retornou .t.

Será que existe algum jeito de alterar a função dbusearea()?

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 30 Jul 2014 13:02
por sygecom
Use o TRY
Exemplo:
TRY
dbusearea(.......)
CATCH
Alert('Ops, verifica sua conexão ai....')
END

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 31 Jul 2014 08:01
por Toledo
cjp escreveu:Será que existe algum jeito de alterar a função dbusearea()?

Bom, ai já não é assunto para este fórum, o correto é no grupo de desenvolvedores do Harbour.

sygecom escreveu:Use o TRY

Verdade, bem lembrado! Mas TRY...CATCH é para xHarbour, com o Harbour tem que usar o BEGIN SEQUENCE...RECOVER.

Exemplo:

BEGIN SEQUENCE
dbusearea(.......)
RECOVER
Alert('Ops, verifica sua conexão ai....')
ENDSEQUENCE

Abraços,

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 31 Jul 2014 14:56
por Nascimento
Amigo toledo testei sua funçao acima so retorna a .f.

será que estou errando em algo?

Proc main()
cls
if IsConnected()

?' TEM NET !!!'

else
?IsConnected()
?' :( NAO TEM NET'

endif

Function IsConnected()
local nFlags := 0, lRet := .f.
if CallDll32( "InternetGetConnectedState", "C:\WINDOWS\system32\WININET.DLL", @nFlags, 0 ) == 1
  if CallDll32( "InternetCheckConnection", "C:\WINDOWS\system32\WININET.DLL", "https://www.google.com",1,0) == 1
    lRet := .t.
  endif
endif
RETURN lRet

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 31 Jul 2014 18:11
por Toledo
Amigo Josivan, eu uso este código em um programa MiniGui e funciona perfeitamente.

Em um outro tópico já discutimos sobre esta função, inclusive fiz algumas alterações nela para evitar usar a hbmisc.lib do Harbour, mas você não deu retorno se testou a função.

http://www.pctoledo.com.br/forum/viewtopic.php?f=4&t=14691&start=60#p86762

Abraços,

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 31 Jul 2014 20:23
por Jairo Maia
Olá Pessoal,

Se a ideia é apenas testar se está conectado, uma forma que acho muito boa é desta forma:
/*
  Compilar: Hbmk2 exemplo.prg -lxhb
*/

Func Main()
? IConectada()
Return Nil

Func IConectada( cAddress )  // Se cAddress = Nil, por padrão checa o google
Local aHosts
InetInit()
If cAddress == Nil
cAddress := "www.google.com.br"
EndiF
aHosts := InetGetHosts( cAddress )
IF aHosts == NIL .or. len(aHosts)=0
InetCleanup()
Return .f.
endif
InetCleanup()
Return .t.

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 31 Jul 2014 22:51
por Nascimento
sim amigo toledo para nao mudar o assunto inicial do topico as funçoes que vc fez no outro topico mesmo sem net mais estando conectada simplismente ao hub retornava a .t.

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 05 Ago 2014 00:26
por cjp
Caro Toledo,

Não estou mais viajando, não tenho como testar mais se com a internet lenta vai dar problema ou não.

Mas fiz um teste simulando um erro proposital dentro do begin sequence, assim:

begin sequence
repl agenda with "a"
recover
?"Erro"
inkey(10)
endsequence


Sendo que nenhuma base de dados está em uso, naturalmente daria erro. Só que ele está chamando o errorsys, não está caindo no recover.

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 05 Ago 2014 07:25
por Toledo
Desculpe, precisa de um desvio do errorsys, então faça assim:

  bError := ErrorBlock( {|e| Break(e) } )
  begin sequence
    repl agenda with "a"
  recover
    ?"Erro"
    inkey(10)
  endsequence
  ErrorBlock( bError )


Abraços,

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 05 Ago 2014 10:38
por cjp
Funcionou. Obrigado.

Isto é uma excelente alternativa para evitar erro no programa. O problema é que tem que colocar isto ponto a ponto, né? Não dá pra fazer isso de forma geral, né?

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 05 Ago 2014 12:19
por Toledo
cjp escreveu:Não dá pra fazer isso de forma geral, né?

Bom, você poderia colocar no seu programa inicial, no menu principal, fazendo a chamada dos outros PRG no menu dentro do BEGIN SEQUENCE, mas ai qualquer erro que ocorrer você vai ficar sem saber o que está ocorrendo, pois o errorsys não será executado.

Abraços,

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 05 Ago 2014 15:56
por alxsts
Olá!

Pode-se tratar todos os erros conhecidos no bloco RECOVER e se não for nenhum deles, tratar genericamente usando o ErrorSys:
#define ERR_ERR1  50001
#define ERR_ERR2  50002
#define ERR_ERR3  50003

LOCAL bError := ErrorBlock( {|e| Break(e) } )
LOCAL oErr

BEGIN SEQUENCE
   repl agenda with "a"
RECOVER USING oErr
   DO CASE
      CASE oErr:genCode == ERR_ERR1
         ? "Erro", ERR_ERR1, oErr:description
      CASE oErr:genCode == ERR_ERR2
         ? "Erro", ERR_ERR2, oErr:description
      CASE oErr:genCode == ERR_ERR3
         ? "Erro", ERR_ERR3, oErr:description
      OTHER
         Eval( bError, oErr )
   ENDCASE

   Inkey(10)
ENDSEQUENCE

ErrorBlock( bError )

(Não testei este código)

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 09 Ago 2014 23:35
por sygecom
Outra opção é tratar o erro no Errorsys.prg
   IF oError:genCode == EG_NOFUNC // não achou a função dentro do sistema
      cMessage:='Erro: ' + ErrorMessage( oError )
      TEXTO_ERRO_PADRAO(@cMessage)
      cLogFile := 'error_'+DTOS(DATE())+StrTran( TIME(), ":", "_")
      MemoWrit( cLogFile+".log", cMessage )

      IF MY_MsgYesNo('Atenção !!! O Sistema encontrou um comportamento estranho com a falta de uma rotina, deseja enviar esse erro para Sygecom agora ?'+ HB_OsNewLine()+;
                     cMessage,30)
         ENVIA_ERRO()
      ENDIF
      RETURN .T.
   ENDIF

   IF oError:genCode == EG_NOALIAS  // NÃO ACHOU O ALIAS ENTÃO ABRE O BANCO COMPARTILHADO
         IF Use_Arq(oError:operation,oError:operation,.T.,.F.,.F.,.T.)=.T.
            RETURN .T.
         ENDIF
   ENDIF

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 15 Ago 2014 22:59
por cjp
Resolvi de uma forma simples: mandar o error.log de dentro do recover. Ficou assim:

bError := ErrorBlock( {|e| Break(e) } )
begin sequence         
DBUSEAREA( .T.,, "SELECT * FROM ativ where data>'"+alltrim(str(year(date()-2)))+"-"+substr(dtoc(date()-2),4,2)+"-"+substr(dtoc(date()-2),1,2)+"'", "ativ")
recover
logerro()
mandmail1("error.log","Erro recuperado com o recover no fazmail")
endsequence            
ErrorBlock( bError )


Só que para isso eu precisei apenas separar uma parte do meu arquivo errorsys.prg em uma função que chamei logerro(), apenas para construir o error.log. Ficou assim:

function logerro
   cMessage := "Ocorreu o erro: "+ansi(cMessage) + Hb_Eol()
   cMessage += "Data..........: "+dtoc(date())+ Hb_Eol()
   cMessage += "Hora..........: "+time() + Hb_Eol()
   cMessage += "Máquina.......: "+netname() + hb_eol()
   cMessage += "Programa......: " + Hb_CmdArgArgV() + Hb_Eol() //+ hb_eol()
   cMessage += ansi("Versão........: ") + vers + Hb_Eol() + Hb_Eol()
   cMessage += ansi("Na função.....: ") + ProcName(2) + Hb_Eol() //+ hb_eol()
   cMessage += "Na linha......: " + NTRIM(ProcLine(2)) + Hb_Eol() //+ hb_eol()
   cMessage += "No prg........: " + procfile(2) + Hb_Eol() + hb_eol()
   cMessage += "Pasta.........: " + CurDir() + Hb_Eol()
   cMessage += ansi("Usuário.......: ") + us + Hb_Eol()
   cMessage += "Base em uso...: " + Alias() + Hb_Eol()
   cMessage += ansi("Área em uso...: ") + alltrim(str(select())) + Hb_Eol()
   cMessage += hb_eol() + ansi("Área 1........: ") + alias(1) + Hb_Eol()
   cMessage += if(!empty(alias(2)),ansi("Área 2........: ") + alias(2) + Hb_Eol(),"")
   cMessage += if(!empty(alias(3)),ansi("Área 3........: ") + alias(3) + Hb_Eol(),"")
   cMessage += if(!empty(alias(4)),ansi("Área 4........: ") + alias(4) + Hb_Eol(),"")
   cMessage += if(!empty(alias(5)),ansi("Área 5........: ") + alias(5) + Hb_Eol(),"")
   cMessage += if(!empty(alias(6)),ansi("Área 6........: ") + alias(6) + Hb_Eol(),"")
   cMessage += if(!empty(alias(7)),ansi("Área 7........: ") + alias(7) + Hb_Eol(),"")
   cMessage += if(!empty(alias(8)),ansi("Área 8........: ") + alias(8) + Hb_Eol(),"")
   cMessage += if(!empty(alias(9)),ansi("Área 9........: ") + alias(9) + Hb_Eol(),"")

   cMessage += Hb_Eol()
   cMessage += "Caminho Percorrido Antes do Erro:"  + Hb_Eol()

   i := 2
   While ( !Empty( ProcName(i) )) //.and. procname(i)#"MAIN" )
         cMessage += "Vindo de......: " + Trim(ProcName(i)) + "(" + NTRIM(ProcLine(i)) + " - " + procfile(i) + ")" + Hb_Eol() + hb_eol()
         i++
   EndDo
   
   cMessage += Hb_Eol()+"Mem¢ria dispon¡vel para valores caracteres: "+alltrim(str(memory(0)))
   cMessage += Hb_eol()+"Maior bloco dispon¡vel para valores caracteres: "+alltrim(str(memory(1)))
   cMessage += Hb_eol()+"µrea dispon¡vel para comandos RUN: "+alltrim(str(memory(2)))

   cMessage += Hb_Eol()
   cMessage += Hb_Eol()

         cMessage += "V¡deo Screen Dump:" + Hb_Eol()
           cMessage += Replicate( '-', nCols -15 ) + Hb_Eol()
           nCellSize := len( Savescreen( 0, 0, 0, 0 ) )
           nRange := ( nCols + 1 ) * nCellSize
           For nCount := 1 To nRows + 1
               cOutString := ''
               cSubString := Substr( cScreen, nStart, nRange )
               For nForLoop := 1 To nRange step nCellSize
                   cOutString += Substr( cSubString, nForLoop, 1 )
               Next
            cMessage += "|" + cOutString + "|" + Hb_Eol()
               nStart += nRange
           Next
           cMessage += Replicate( '-', nCols -18 ) + Hb_Eol()
   Use
   Ferase( "error.log")
   MemoWrit( "error.log", cMessage )
return

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 11 Set 2014 16:46
por cjp
Amigos,

Como havia dito, estou usando com êxito esse begin sequence para contornar erros. Em tudo está funcionando sem problema.

Mas agora tentei usar em uma outra função, desta forma:

               if upper(exclusivo)#"S"
                  if select(bssembarra) = 0
                     bError := ErrorBlock( {|e| Break(e) } )
                     begin sequence
                           use &nomebase. shared
                     recover
                         logerro()
                           mandmail1("error.log","Erro na função usebase contornado com o recover do begin sequence 19142",,2)
                         return .f.
                    endsequence
                    ErrorBlock( bError )
                  else
                     DbSelectArea(bssembarra)
                 exit
                  endif
            else
               if select(bssembarra) = 0
                     bError := ErrorBlock( {|e| Break(e) } )
                     begin sequence
                           use &nomebase. //new
                     recover
                         logerro()
                           mandmail1("error.log","Erro na função usebase contornado com o recover do begin sequence 19157",,2)
                         return .f.
                     endsequence
                     ErrorBlock( bError )
               else
                     DbSelectArea(bssembarra)
                 if exclusivo="S"
                   use
                   use &nomebase. //new
                 else
                   exit
                endif   
               endif
            endif    
               if neterr()
                  vezusb++
                  @ maxrow()-1,1 clear to maxrow()-1,maxcol()-1
                  @ maxrow()-1,1 say "Base "+upper(nomebase)+" ocupada; aguarde liberação ("+alltrim(str(vezusb))+")"
              inkey(8)
              @ maxrow()-1,1 clear to maxrow()-1,maxcol()-1
                  desiste:=inkey(8)
                  if desiste= 27 //K_ESC
                     conf="N"
                     @ maxrow()-2,1 clear to maxrow()-1,maxcol()-1
                     @ maxrow()-1,5 say "Confirma abandono da tentativa da utilização?"get conf pict "@!"
                     read
                     @ maxrow()-2,1 clear to maxrow()-1,maxcol()-1
                     if conf="S"
                   retf="S"
                  exit
*                        return .f.
                     endif
                  endif
               else
                  exit
               endif


Só que, neste caso, ao invés de entrar no recover, o programa está fechando automaticamente, e sem dar qualquer mensagem de erro.

Notei que isso ocorre sempre que a base está em uso por outro programa. Portanto, quando deveria entrar no neterr(), esperando a liberação da base. Mas daí, com o begin sequence, ele já fecha o programa logo.

Alguém saberia me dizer qual a razão disso? E o que eu faço para consertar isso?

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 12 Set 2014 03:26
por alxsts
Olá!

Embora o assunto deste tópico já tenha sido desviado, vou responder a mensagen anterior.
cjp escreveu:...Só que, neste caso, ao invés de entrar no recover, o programa está fechando automaticamente, e sem dar qualquer mensagem de erro...
No momento em que este erro ocorre, o manipulador padrão de erros já é o teu e não mais o ErrorSys. Não sei porque mas NetErr() (DOS Error 32) não é ativado quando ocorre esse erro (arquivo em uso por outra sessão). Assim, o erro não é tratado pelo teu manipulador de erro e não existe outro manipulador. Então, o controle é passado ao sistema operacional o programa é fechado. Teria que tratar "na unha", testando o DOS Error 32.

Veja o exemplo abaixo e adapte-o à suas necessidades.
#define DB_SHARED      .T.
#define DB_EXCLUSIVE   .F.

FUNCTION Main()

   AltD()
   
   SetMode( 50,100)
   OpenTable( "CadOs", { "CadOs" }, NIL, NIL, DB_EXCLUSIVE )
   
   Browse()
   
   If Select( "CadOs" ) > 0
      DbCloseArea( "CadOs" )
   Endif
   
   CLS
   
   RETURN NIL
//-------------------------------------------------------------------------------------------------------------
FUNCTION OpenTable( cName, aIndexList, cAlias, lNewArea, lShared, cDriver, lReadonly )

   LOCAL bError := ErrorBlock( {|e| Break(e) } )
   LOCAL oErr
   LOCAL nPos, nLen
   LOCAL lRet := .F.

   IF ! Empty( cName )
      // verificação dos parâmetros
      lShared := If( lShared == NIL, .T., lShared )
      lNewArea := If( lNewArea == NIL, .T., lNewArea )
      lReadonly := If( lReadonly == NIL, .F., lReadonly )
      cAlias := If( cAlias == NIL, cName, cAlias )
      cDriver := If( cDriver == NIL, "DBFNTX", cDriver )
      aIndexList := If( Empty( aIndexList ), {}, aIndexList )

      BEGIN SEQUENCE

         // Abre a tabela
         IF lNewArea
            DbSelectArea( 0 )
         ENDIF
         
         // DBUSEAREA( lNewArea, cDriver, cName, cAlias, lShared, lReadonly )    ou
         IF lShared
            USE (cName) ALIAS (cAlias) SHARED VIA (cDriver)          // não é necessário usar o macro operator (&) ...
         ELSE
            USE (cName) ALIAS (cAlias) EXCLUSIVE VIA (cDriver)       // ... basta colocar as variáveis entre parêntesis...
         ENDIF
         
         // Abre eventuais índices.
         // Abre de traz para a frente. Assim, o primeiro índice da lista se torna a ordem atual...
         IF ( nLen := Len( aIndexList ) ) > 0
            FOR nPos := nLen TO 1
               DbSetIndex( aIndexList[ nLen ] )
            NEXT
         ENDIF

         lRet := .T.

      RECOVER USING oErr
         IF oErr:osCode == 32
            NetErr( .T. )      //   é possível setar NetErr() para True mas, não se tem detalhes do erro...
         ENDIF                 // ... mas se existe o objeto erro, com os detalhes do erro, é melhor explorar ele
         
         ErrShow( oErr )       // passando o objeto erro para uma rotina de erro ou geração de logs

         // Dispara o erro com o manipulador padrão.
         Eval( bError, oErr )  // No caso de oErr:osCode == 32, nada acontece. Não olhei o ErrorSys.Prg padrão mas acho que ele não trata isso...
      ENDSEQUENCE
   END

   // Restaura o manipulador de erros padrão
   ErrorBlock( bError )

   RETURN lRet
//-------------------------------------------------------------------------------------------------------------

STATIC FUNCTION ErrShow( oErr )

   /*
   oErr:args            An array of function or operator arguments
   oErr:canDefault      Indicates whether or not default recovery is available
   oErr:canRetry        Indicates whether or not a retry is possible after an error
   oErr:canSubstitute   Indicates if a new result can be substituted after an error
   oErr:cargo           User-definable variable
   oErr:description     Character description of the error condition
   oErr:filename        Name of the file associated with the error
   oErr:genCode         CA-Clipper error code number
   oErr:operation       Character description of the failed operation
   oErr:osCode          Operating system error code number
   oErr:severity        Indicates error severity
   oErr:subCode         Subsystem-specific error code number
   oErr:subSystem       Character description of the subsystem generating the error
   oErr:tries           Number of times the failed operation has been attempted
   */

   HB_Alert( { "Ocorreu o erro : " + oErr:subSystem + "/" + Ltrim(Str(oErr:subCode)), "DOS Error " + LTrim(Str(oErr:osCode)), "Descricao: " + oErr:description, "Operacao: " + oErr:Operation, "Arquivo: " + oErr:fileName },{ 'Ok' },"W+/B", 15 )

   RETURN NIL
//-------------------------------------------------------------------------------------------------------------

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 12 Set 2014 23:18
por cjp
Obrigado, meu caro.

Mas fiquei com duas dúvidas:

1) quando vc diz "No momento em que este erro ocorre, o manipulador padrão de erros já é o teu e não mais o ErrorSys", isso significa que o erro ocorre na linha "use &nomebase.", certo? E este comando está dentro do begin sequence, certo? Bom, mas daí, dando erro dentro do begin sequence, ele não deveria desviar pro recover? E daí executar a função mandmail1?

2) No programa que vc postou, não está da mesma forma que o meu? Quero dizer a linha "USE (cName) ALIAS (cAlias) SHARED VIA (cDriver)" está entre o begin sequence e o RECOVER USING oErr, não?

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 13 Set 2014 12:12
por alxsts
Olá!

A resposta é sim para as duas questões.

Creio que ocorre algum erro dentro da MandMail1 e, como não há tratamento, o programa é encerrado.

Restaure o manipulador de erros padrão antes de invocar a função e veja o que acontece.
      RECOVER USING oErr

         // Restaura o manipulador de erros padrão
         ErrorBlock( bError )

         MandMail1()

      ENDSEQUENCE
   END


Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 13 Set 2014 12:45
por cjp
Eu já fiz isso. Retirando o manipulador, volta ao normal, não há qualquer erro na mandmail1.

Poderia ser algum erro gerado no próprio manipulador?

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 13 Set 2014 14:22
por alxsts
Olá!

O que é "volta ao normal"?

Se na MandMail() não tem erro, talvez tenha na LogErro(). Teste este código:
   LOCAL bError := ErrorBlock( {|e| Break(e) } )

   BEGIN SEQUENCE
   
      ? 1 / 0

   RECOVER USING oErr
      // Restaura o manipulador de erros padrão
      ErrorBlock( bError )

      LogErro()

      MandMail1()
   
   ENDSEQUENCE

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 13 Set 2014 16:05
por cjp
Quando disse "volta ao normal" quis dizer que não dava mais erro.

Mas vc tinha razão: tinha erro na logerro(). Corrigi e resolveu. Agora vou testar na função que eu estava usando.

Mas antes, fiquei com uma dúvida: o erro que tinha era por falta de definição de uma variável (cMessage), que está definida no errorsys. Quando o logerro() é chamada da errorsys, sem problema. Mas quando ela era chamada do recover do meu manipulador, dava problema. Tentei definir essa variável dentro do próprio logerro(), do jeito que está no teu exemplo anterior, mas não funcionou. Veja, fiz assim:

cMessage := If( cMessage == NIL, "", cMessage )


Não era pra funcionar assim? Por que continuou dando variável inexistente?

Agora eu defini ela no início do programa, e deu certo. Mas eu preferia fazer desta forma que vc fez.

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 13 Set 2014 18:44
por alxsts
Olá!
cjp escreveu:Tentei definir essa variável dentro do próprio logerro(), do jeito que está no teu exemplo anterior, mas não funcionou.
Neste caso você não definiu a variável. Apenas testou se o conteúdo da variável estava NIL ou não. Como a variável não existe neste instante, gera erro.

Naquele exemplo acima, foram testadas as variáveis que a função recebeu como parâmetros de entrada. Sempre que uma função recebe parâmetros são criadas variáveis do tipo LOCAL, com os nomes dos parâmetros recebidos ou seja, são declaradas variáveis locais à função. Veja:
FUNCTION Teste()

   ? MessageShow( "Brasil" )

RETURN NIL
//--------------------------------------------

FUNCTION MessageShow( cMessage )

   cMessage := IF( cMessage == NIL, "NIL", cMessage )   // ou cMessage := IF( Empty( cMessage ), "NIL", cMessage )

   Alert( cMessage )

RETURN NIL
//--------------------------------------------
Resumindo: a melhor prática é sempre declarar todas as variáveis que o programa utiliza. Use sempre variáveis dos tipos LOCAL e/ou STATIC. Com os avanços do Harbour, é possível especificar o tipos das variáveis definidas. Ainda não podemos dizer que o Harbour é uma linguagem fortemente tipada mas, usar este recurso faz com que o compilador gere avisos (warnings), dependendo das configurações de compilação, quando o programador faz atribuições de valores de dados às variáveis diferentes dos tipos declarados.
LOCAL aArray AS Array
LOCAL nVal AS Numeric
LOCAL dDate AS Date
LOLAL cVal AS Character

   // as linhas abaixo gerarão warnings pois os dados atribuídos às variáveis são diferentes dos declarados
   aArray := "Teste"
   nVal := "10"
   dDate := DtoS( Date() )
   cVal := Date()

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 14 Set 2014 02:21
por cjp
Entendido. Muito obrigado.

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 18 Out 2014 00:36
por cjp
Caros colegas,

Por favor, observem este trecho de uma função minha:

         bError := ErrorBlock( {|e| Break(e) } )
         begin sequence
              append blank
              repl arqmand with am
              repl assmail with asm+"; bsusonow: "+alltrim(str(bsusonow))+"; área: "+alltrim(str(select()))+"; data: "+dtoc(date())+"; hora: "+time()
              repl maildst with md
             repl anexo with an
             repl tela with cMessage
         recover
              cMessage := ErrorMessage(e)
             logerro()
            mandmail1("error.log","Erro recuperado com o recover no fazmail",,2)
         endsequence
         ErrorBlock( bError )


A ideia é contornar eventuais erros no primeiro trecho, o que tem acontecido satisfatoriamente.

O único problema é que, quando ocorre o erro, eu precisaria saber qual é o erro. Por isso coloquei:

              cMessage := ErrorMessage(e)


Daí, na função logerro() eu crio um arquivo de log com vários detalhes que o programa me envia automaticamente com a função mandmail1().

O problema é que cMessage está retornando vazio. E assim eu não consigo saber qual o erro que está dando dentro da sequência.

Em outros testes, acontece também de o programa fechar sem dar nenhum erro. Daí eu restaurei o ErrorBlock( bError ) e deu o seguinte erro:

Error BASE/1003  Variável não existe: E


Se eu bem entendi, esse E não seria o e do bError := ErrorBlock( {|e| Break(e) } )? Se for, por que seria uma variável inexistente?

Alguém me ajuda?

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 22 Out 2014 17:02
por Toledo
Inácio, se você estiver usando o comando bError := ErrorBlock( {|e| Break(e) } ), infelizmente não tem como saber qual o erro que ocorreu, pois o comando Break(e) vai encerrar a chamada do ERRORSYS e desviar a execução do programa para depois do comando RECOVER. Então, sem a execução do ERRORSYS, não tem como saber qual foi o erro.

Quando lhe foi sugerido o uso do bError := ErrorBlock( {|e| Break(e) } ), foi exatamente porque você não queria que o ERRORSYS fosse executado.

Então, ou você usa o bError := ErrorBlock( {|e| Break(e) } ) e evitar que o ERRORSYS seja executado, ou retira a linha do ErrorBlock e deixa o ERRORSYS ser executado, onde você poderá saber qual o erro que está ocorrendo, criar o log e enviar o e-mail.

Abraços,

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 22 Out 2014 17:23
por cjp
Entendi.

Mas tem como executar o errorsys() e depois retornar, com o recover ou de alguma outra forma, para o ponto do programa onde deu erro e prosseguir normalmente?

O que eu preciso evitar é a interrupção do programa pelo erro, o que o begin sequence está fazendo maravilhosamente bem. Mas também preciso do log do erro. Dá pra juntar o melhor dos dois mundos?

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 22 Out 2014 18:17
por Toledo
cjp escreveu:Mas tem como executar o errorsys() e depois retornar, com o recover ou de alguma outra forma, para o ponto do programa onde deu erro e prosseguir normalmente?

Sim, é possível, basta modificar o ERRORSYS e trocar o comando QUIT por Break(e). Mas neste caso, o uso do comando Begin sequence... Recover... endsequence será obrigatório em todos os módulos do seu programa, porque quando ocorrer qualquer erro tem que ter o Recover para retornar a execução do programa, caso contrário, o erro ocorrer sem existir um Recover para retorno, a execução vai retornar no mesmo ponto onde ocorreu o erro e ai se o erro persistir será chamado novamente o ERRORSYS (ficando num LOOP infinito).

Geralmente quando o ERRORSYS tem o QUIT trocado por Break(e), o Begin Sequence é colocado no menu do programa inicial, logo após o comando MENU TO. Assim quando ocorrer qualquer erro no programa, a execução vai retornar para o menu no programa inicial. Já o comando QUIT no ERRORSYS vai finalizar o programa, retornando para o DOS.

Abraços,

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 23 Out 2014 01:01
por alxsts
Olá!

Inácio: creio que o que você não está entendendo é o funcionamento, a mecânica da coisa.

Sempre que um erro é detectado, o Clipper ou (x)Harbour automaticamente gera um objeto erro e passa este objeto erro ao manipulador de erros ativo. Se for o ErrorSys padrão, o objeto erro vai ser passado para ele. Se houver um manipulador de erros personalizado, como nos exemplos mostrados, o objeto erro será passado para este manipulador personalizado.

Veja:

1 - você define o seu manipulador de erros personalizado com bError := ErrorBlock( {|e| Break(e) } ). Neste momento, o ErrorSys padrão é armazenado em bError e um novo manipulador de erros se torna ativo.
2 - durante o processamento da aplicação, ocorre um erro qualquer. O Clipper ou (x)Harbour intercepta o erro e gera um objeto da classe Error
3 - em seguida, o Clipper ou (x)Harbour passa o objeto Error gerado para o manipulador de erros ativo. Supondo que o manipulador ativo tenha sido definido com bError := ErrorBlock( {|e| Break(e) } ), o objeto Error será recebido como o parâmetro e ( {|e| Break( e ) } ) no code block do manipulador de erros e será repassado como parâmetro de entrada da função tratadora de erros. Neste caso, está sendo usada a função Break() mas poderia ser uma outra, definida por você mesmo. Veja que a função recebeu o objeto de erro como parâmetro de entrada ( Break( e ) )
4 - Para que você possa capturar e tratar este objeto Erro gerado em sua aplicação, é necessário receber este objeto Erro. Este é o ponto que acho que você ainda não percebeu. Para receber o objeto, é necessária a cláusula RECOVER USING. Quando Break( e ) é executado, o objeto Erro é passado para a variável declarada (neste caso oErr) e fica disponível para o teu programa tratar
LOCAL oErr

BEGIN SEQUENCE
.
.
.
RECOVER USING oErr
.
.
.
ENDSEQUENCE

5 - com este objeto Erro em mãos, você poderá tratar o erro de forma muito flexível, explorando todas as propriedades do objeto Erro (listadas no link acima), sem ter que recorrer ao GetSys. Se preferir recorrer a ele, basta executar um Break( bError ) - lembra que você guardou o manipulador padrão em bError?
6 - exemplo de operação que dá erro e permite que se tente novamente:
FUNCTION Teste()

   LOCAL bError := ErrorBlock( {|e| Break(e) } ), nOption

   Altd()
   
   CLS

   WHILE .T.

      BEGIN SEQUENCE
         
         ?

         FOR nOption := 10 TO 0 STEP -1
            ? 10 / nOption
         NEXT

      RECOVER USING oErr

         nOption := Alert( "Ocorreu o erro " + ;
                           oErr:subsystem + "/" + ;
                           Ltrim( Str( oErr:subCode ) ) + ;
                           " - " + oErr:description +  ;
                           ' na operação "' + oErr:operation + '"', { " Continuar ", " Fechar "} )
     
   
         //LogErro()

         //MandMail1()
   
         IF nOption != 1
            EXIT
         ELSE
            LOOP
         ENDIF

      ENDSEQUENCE
   ENDDO

   // Restaura o manipulador de erros padrão
   ErrorBlock( bError )

   RETURN NIL

Erro em acesso ao banco de dados com internet lenta

MensagemEnviado: 24 Out 2014 00:23
por cjp
De fato eu não tinha ainda entendido bem como isso funcionava. Muito obrigado pela excelente aula, Alexandre.

Com o recover using funcionou.

Muito obrigado a todos que ajudaram.