Página 1 de 1

contornar um erro

Enviado: 08 Nov 2012 10:14
por Amparo
ola amigos

estou convertendo um programa feito em clipper 5.3 para Harbour 3.0.0 (Rev. 16951)

ao executar ocorre o erro abaixo, gostaria de saber se tem como pular este erro e continuar a operaçao por exemplo

Código: Selecionar todos

 Error DBFCDX/1010  Read error: C:\TDINI\DADOS\CONTAS.fpt

                          Quit
estou dando um comando para imprimir um campo memo e quando chega em um determinado registro da o erro

queria colocar tipo

do while !contas->( eof() )

if erro contas.fpt

grava em um arquivo texto o recno() do registro

else

imprime

endif

...

alguem poderia me dar uma ideia

contornar um erro

Enviado: 08 Nov 2012 11:54
por Jairo Maia
Olá Amparo,

Acho que poderia ser tratado diretamente no ERRORSYS. Veja o errorsys em anexo, e procure pela seção que diz: Tratativa de erro fpt. Dê uma estudada nessa sugestão. Não consigo testar, pois não tenho uma situação que ocorre o erro 1010.

Espero que ajude.

contornar um erro

Enviado: 08 Nov 2012 13:46
por alxsts
Olá!

Veja se o código abaixo te ajuda. Não compilei nem testei...

Código: Selecionar todos

#include "error.ch"
#include "fileio.ch"

// a linha abaixo eh para Harbour. Em xHarbour não precisa
//#xtranslate THROW( <oErr> ) => ( Eval( ErrorBlock(), <oErr> ), Break( <oErr> ) )

FUNCTION Main()

   LOCAL nHandle, cFile := 'Contas'                                        

                                                 
   USE (cFile) SHARED NEW ALIAS contas                             
                                                 
   contas->( DbGoTop() )                                    

   WHILE contas->( ! Eof() )                                  

      TRY // em Harbour acho que é Begin Sequence With { |e| Break(e) }                                              

         // Impressão                                
         MemoPrint()                                       
                                                 
         contas->( DBSkip() )                                   

      CATCH oErr                                          

         IF oErr:SubCode == 1010                                    
            // Erro de leitura no FPT                                  
            // cria temporario para gravar os erros                           
            IF nHandle == NIL                                      
               nHandle := FOPEN("ErrosFPT.txt", FO_READWRITE + FO_SHARED)                
               IF FERROR() != 0                                     
                  ? "Falha ao abrir arquivo para gravação de erros, DOS error ", FERROR()        
                  __QUIT()                                        
               ENDIF                                           
            ENDIF                                            
                                                 
            FWRITE( nHandle, StrZero( contas->( Recno() ), 6 ) + Chr(13) + Chr(10), 8 )                   
       
            contas->( DbSkip() ) // ignora registro                          
                                                 
            LOOP                                    
         ELSE                                              
            // Outro erro qualquer                                   
            ? "*** Erro em " + oErr:moduleName + " ***"                         
            ?                                              
            ? "Codigo ", oErr:subsystem + "/" + Ltrim(Str(oErr:subcode)), " Descricao ", ( oErr:description )
            ?                                              
            IF ! Empty(oErr:aaStack)                                  
               Aeval( oErr:aaStack, { |e| QOut( "Chamado de " + e[2] + "(" + Ltrim(Str(e[3] ) ) + ")" ) } )
            ENDIF                                            
                                                  
            EXIT
         ENDIF                                             
                                                 
      END                                               
   ENDDO

   IF nHandle != NIL                                      
      FCLOSE( nHandle )
      MemoEdit( 10,10, 20,20, Memoread( "ErrosFPT.txt" ) )
   ENDIF                                            

   RETURN NIL                                            
//-------------------------------------                              
STATIC FUNCTION MemoPrint()                                    
   // <procedimentos>
   ? obs_cli
 RETURN NIL                                           
//-------------------------------------
Editado para testar o código. Não consegui reproduzir o erro.

contornar um erro

Enviado: 10 Dez 2012 00:19
por cjp
Jairo e demais colegas,

Tenho enfrentado problema semelhante ao mencionado neste tópico e há tempos venho tentando uma solução para contornar o erro de criação de arquivo, evitando que o problema feche por erro neste caso.

Testei à exaustão a tua função, mas estou com um problema: o return .t. faz com que, aparentemente, o programa volte a tentar efetivar a criação do arquivo, gerando recursividade no erro. Parece que ele equivale à opção Retry que consta do errorsys.prg original.

Também testei a função sugerida pelo alxst, com o __quit(). Só que aí ele fecha o programa, não o contornando.

Eu precisava de uma forma de voltar ao programa, no ponto seguinte ao que gerou o erro, ou seja, pulando o ponto do erro, à semelhança do que foi mencionado pelo Amparo.

Tem um jeito de fazer isso?

contornar um erro

Enviado: 10 Dez 2012 06:03
por Jairo Maia
Olá Inácio,

Bom, se tem uma coisa que me deixa maluco é quando tento entender esse TRY. Parece trocadilho, mas não é, realmente acho que desisti de TENTAR entender o TRY, assim, não sei opinar sobre a sugestão do colega Alexandre (alxsts).

Quanto a minha sugestão, não sei se vai funcionar, mas tente alterar o return .t. desta forma:

Código: Selecionar todos

If ( e:CanDefault )
 Return .f.
Else
 Quit
EndIf
Outra coisa, que tipo de erro você está tendo que precisa continuar?

contornar um erro

Enviado: 10 Dez 2012 08:32
por rochinha
Amiguinhos,

Para contornar o erro sem manipular o errorsys.prg voces devem criar as tabelas pela nova aplicação.

Ou seja, não acesse diretamente os arquivos da aplicação antiga, mas sim renove as estruturas, criando-as pelo novo aplicativo e appendando os dados antigos.

Os arquivos FPT da aplicação antiga não são tão compativeis aos da aplicação nova.

contornar um erro

Enviado: 10 Dez 2012 08:41
por Pablo César
É bom lembrar que se ocorreu um erro é porque algo está errado e os erros devem ser corrigidos e não contornados. Contornar o erro, isto é, continuar a execução do programa mesmo com erro, pode vir acontecer outros tipos de inconvenientes. Os erros causado pelo ftp (provenientes dos campos memos) já são de longa data os relatos dos colegas. A solução seria passar a não usá-los dentro do dbf.

contornar um erro

Enviado: 12 Dez 2012 01:00
por cjp
Jairo e Rochinha, desculpem, mas não entendi bem a solução apontada por vocês.

A minha questão, Pablo, é a seguinte: tenho diversos tipos de erros frequentes no programa, erros derivados de problemas com as bases de dados, principalmente. Queria evitar a interrupção frequente do programa por erros. A ideia é que o programa do usuário simplesmente me comunique o erro ocorrido (o que já está implantado) e continue rodando normalmente para as demais tarefas, deixando de fazer apenas a tarefa com problema, o que é perfeitamente factível. A única coisa que falta implementar é realmente fazer com que o errorsys retorne para o programa, contornando o erro.

Exemplo: um dos erros muito comuns é o "create error", ou "erro de criação", que ocorre muito num ponto do programa em que uso a função copy to. Neste caso, eu queria que o programa só ignorasse o copy to e continuasse rodando, o que ocorreria normalmente, sem problemas para o resto do programa. Como eu faria para prosseguir?

contornar um erro

Enviado: 12 Dez 2012 02:14
por rochinha
Amiguinho,

Eu entendi o que voce postou, mas entendo que erro é erro e temos de resolvê-lo.

Se deu erro, um cálculo critico não será retornado, um campo critico não terá sua informação gravada.

Talvez o que voce precise seja algo parecido com o trecho abaixo:

Código: Selecionar todos

/*************
*	ErrorSys()
*
*	Note:  automatically executes at startup
*/
proc ErrorSys()
    ErrorBlock( { | e | ErrorDialog( e ) } )
    return

proc ErrorLink()
    return

/*************
*   ErrorDialog()
*/
static function ErrorDialog( e ) // -> logical or quits App.

   local oDlg, oLbx, oFont
   local lRet    // if lRet == nil -> default action: QUIT
   local n, j, cMessage, aStack := {}
   local oSay, hLogo
   local nButtons  := 1
   local cErrorLog := ""
   local aVersions := GetVersion()
   local aTasks
   local aRDDs, nTarget, uValue
   local StackMessage := ""
   local oOldError
   local cRelation
   local lIsWinNT := IsWinNT()
   public lWin2000, lNaoFecha := .f.

   #include "nfwh28p.prg"

    // neste caso retorna sempre sem erro
    // #define EG_UNSUPPORTED  30
    // #define EG_LIMIT        31
    // #define EG_CORRUPTION   32
    // #define EG_DATATYPE     33
    // #define EG_DATAWIDTH    34
    // #define EG_NOTABLE      35
    // #define EG_NOORDER      36
    // #define EG_SHARED       37
    // #define EG_UNLOCKED     38
    // #define EG_READONLY     39
    // Retorna 0 como padrao para erro de divisao
    // if ( e:genCode == EG_* )
    //     return 0
    // endif

   // check for printer error
   if e:genCode == EG_PRINT
      //return PrintError()
      return 0
   endif

   // Retorna .f. padrao para erro de abertura por inxistencia do arquivo
   if ( e:genCode == 4 )
      NetErr( .t. )
      return .f.
   endif

   // by default, division by zero yields zero
   if ( e:genCode == EG_ZERODIV )
      return 0
   end

   if e:SubCode = 1012 // Arquivo nao esta em uso
      //USE (e:Filename) SHARED NEW
      //return .f.
   endif

   if e:SubCode = 1021 // Data Width Error
      //qCampo := e:Operation
      //MsgStop( "A variavel ou campo "+qCampo+" receberá valor 0(ZERO)"+CRLF+;
      //         "Motivo:"+CRLF+;
      //         "Campo na tabela "+dbf()+" com tamanho menor que o"+CRLF+;
      //         "dado sendo passado!" ,"Atencao" )
      //_FIELD->&qCampo := 0
      //return .f.
   endif

   if e:SubCode = 1022 // Lock Required
      //MsgStop( "lockrequerido." )
      //lock()
      //return .f.
   endif

   if e:SubCode = 1003 // Variavel nao encontrada
      //cDataset := " "
      //cError   := "               "
      //qCampo   := e:Operation
      //MsgGet( "Tipo de Dado:", qCampo, @cDataset )
      //MsgGet( "Conteudo:", qCampo, @cError )
      //STORE cError TO &(qCampo)
      //return 0 // .f.
   endif

   if e:SubCode = 1068 // Array Access
      //qCampo := e:Operation
      //MsgStop( "A variavel ou campo "+qCampo+" receberá valor 0(ZERO)"+CRLF+;
      //         "Motivo:"+CRLF+;
      //         "Campo na tabela "+dbf()+" com tamanho menor que o"+CRLF+;
      //         "dado sendo passado!" ,"Atencao" )
      //_FIELD->&qCampo := 0
      //return 0
   endif

   // for network open error, set NETERR() and subsystem default
   if ( e:genCode == EG_OPEN .and. ;
      ( e:osCode == 32 .or. e:osCode == 5 ) .and. ;
        e:canDefault )
      NetErr( .t. )
      return .f.
   end

   if ( e:osCode = 5 )
      return 0
   end
   if ( e:osCode >= 50 .and. e:osCode <= 55 )
      return 0
   end

   // for lock error during APPEND BLANK, set NETERR() and subsystem default
   if ( e:genCode == EG_APPENDLOCK .and. e:canDefault )
      NetErr( .t. )
      return .f.       // OJO SALIDA
   endif

   // insufficient file handles is the developer's responsibility...
   if e:genCode == EG_OPEN .and. e:osCode == 4
      Alert("There are not enough file handles for this application  ;" + ;
            "to continue.  The CLIPPER environment variable should   ;" + ;
            "allow for the maximum number of files to be opened, as  ;" + ;
            "should the FILES= statement in your CONFIG.SYS file.    ;" + ;
            "If you are running on a Novell network, you should also ;" + ;
            "check the FILE HANDLES= statement in the SHELL.CFG file.", ;
            { "Exit to DOS" })
   endif
Veja que o mesmo possui várias verificações de códigos de erros e apresenta alguma solução.

Encontrei este código, tentei usá-lo, mas não obtive nenhum resultado, ou seja, aumentei os meus problemas.

Veja outro trecho:

Código: Selecionar todos

FUNCTION undef_error( a1, a2, a3, a4, a5 )
   ret_row = row()
   ret_col = col()
   sounderr()
   errorscr = savescreen(17,10,24,70)
   @ 17,10 clear to 24,70
   @ 17,10 to 24,70 double
   @ 17,12 say "< OCORRENCIA DE ERRO ON-LINE >"
   @ 19,12 say "ocorreu um &a3. no programa/funcao"
   @ 20,12 say "modulo &a1., no arquivo "+procfile()+" na linha "+alltrim(str(a2))
   DO CASE
      CASE "UNDEFINED IDENTIFIER" $ upper(a3)
           DO WHILE .t.
              @ 23,12 say "Insira tipo de dado de &a5. (DNCL)"
              dataset = upper(chr(inkey(0)))
              IF     dataset = "D"
                     error = ctod("  /  /  ")
                     errpic= "99/99/99"
              ELSEIF dataset = "L"
                     error = .f.
                     errpic= ""
              ELSEIF dataset = "N"
                     error = 1000000000.000000 - 1000000000.000000
                     errpic= "999999999999.999999999999"
              ELSEIF dataset = "C"
                     @ 23,12 say space(len("Insira o tipo de dado de &a5. (DNCL)"))
                     error = ctod("  /  /  ")
                     error1= 0
                     @ 23,12 say "Insira tamanho da string => " get error1 valid error1 >= 1 .and. error1 < 3000
                     READ
                     @ 23,12 say "                            "
                     error = space(error1)
                     errpic= if(error1 > 20, "@S20", "@X")
              ELSE
                     LOOP
              ENDIF
              EXIT
           ENDDO
           @ 23,12 say space(len("Insira o tipo de dado de &a5. (DNCL)"))
           @ 23,12 say "Insira o novo valor para &a5. =>" get error pict errpic
           READ
           PUBLIC &a5.
           STORE erro TO &a5.
           IF     dataset = "L"
                  errmess = "STORE "+if(error,".t.",".f.")+" TO &a5."
           ELSEIF dataset = "D"
                  errmess = "STORE ctod("+alltrim(strvalue(error))+") TO &a5."
           ELSEIF dataset = "C"
                  errmess = "STORE ["+alltrim(strvalue(error))+"] TO &a5."
           ELSE
                  errmess = "STORE "+alltrim(strvalue(error))+" TO &a5."
           ENDIF
   ENDCASE
Estes trechos eram usados em aplicativos antigos, e a sua caracteristica era a de perguntar ao usuário, quando da ocorrencia de um erro, o que deveria ser feito.

Mas isto apesar de parecer legal, só aumenta o suporte, pois se os erros se repetem muito em uma mesma rotina e as variáveis sofrem mudança aleatória, a todo momento voce deverá estar ajudando o usuário a completar os dados.

Se o usuário pensar que pode resolver sozinho ele irá colocar o que acha que deve e voce terá uma salada de problemas em suas tabelas.

Erros intermitentes são mais dificeis de se resolver pois seus dados são aleátórios.

Erros fixos, são de melhor detecção e solução.

Seu sistema deve possuir um log ou um meio de salvar o arquivo de resposta de erro de forma que voce possa analisá-lo.

O melhor é se quando o erro ocorrer é voce fazer com que sua aplicação envie o arquivo para voce por email.

Desta forma após o primeiro erro, quando o usuário for lhe reclamar sobre o segundo voce já estará a par antes dele.

Eu só consegui sanar os erros de meu sistema por meio da captação do arquivo de erros e do seu envio direto para mim.

Contornar parece ser interessante, mas pode ser viciante e permitir que a falha seja algo normal.

Como os amigos colocaram antes. Resolver é o caminho.

contornar um erro

Enviado: 13 Dez 2012 23:58
por cjp
Pra te ser sincero, não entendi bem os exemplos que vc postou. Tentei compilar, mas deu alguns erros de funções desconhecidas. Até desabilitei as funções e consegui compilar, mas dá erro de recursividade, conforme abaixo:

Código: Selecionar todos

Erro irrecuper vel 9003: Muitas chamadas recursivas ao manipulador de erros
Called from ERRORDIALOG(52) in errors2.prg
Called from (b)ERRORSYS(7) in errors2.prg
Called from ERRORDIALOG(52) in errors2.prg
Called from (b)ERRORSYS(7) in errors2.prg
Called from ERRORDIALOG(52) in errors2.prg
Called from (b)ERRORSYS(7) in errors2.prg
Called from ERRORDIALOG(52) in errors2.prg
Called from (b)ERRORSYS(7) in errors2.prg
Called from ERRORDIALOG(52) in errors2.prg
Called from (b)ERRORSYS(7) in errors2.prg
Called from ERRORDIALOG(52) in errors2.prg
Called from (b)ERRORSYS(7) in errors2.prg
Called from ERRORDIALOG(52) in errors2.prg
Called from (b)ERRORSYS(7) in errors2.prg
Called from ERRORDIALOG(52) in errors2.prg
Called from (b)ERRORSYS(7) in errors2.prg
Called from MAIN(56) in AGENDA.PRG
------------------------------------------------------------------------
Mas o que eu queria que vc entendesse é o seguinte: eu trato o erro. O meu errorsys (veja abaixo) já me informa o erro. O que eu queria apenas era evitar que o programa interrompesse pelo erro.

Veja: meu programa roda as funções A, B, C, D, E... Digamos que dá um erro na função B. Eu gostaria que ele, depois de me informar o erro, prosseguisse na execução das funções C, D, E... entende?

contornar um erro

Enviado: 14 Dez 2012 01:10
por rochinha
Amiguinho,

Os trechos colocados são realmente somente fragmentos de códigos completos, somente para voce entender em que pontos são colocadas algumas verificação para suplantar/contornar algumas mensagens de erro.

É necessário analisar e retirar dos fragmentos e testar, testar muito, em seu errorsys original.

É válido entender que alguns erros, são considerados criticos e não oferecem "tentar denovo" por necessidade de finalizar o aplicativo.

O segundo bloco, praticamente coloca a frente do usuário uma interface de resposta para burlar o problema.

Mas isto coloca em jogo a credibilidade do aplicativo e por consequência, também a nossa.

- Se existe um replace para um campo que não está na tabela, esta deve ser criada e voce tera de montar uma rotina ferradissima para que o mesmo seja criado.
- Se existe erro de argumento passado para uma variavel e a mesma deveria possuir outro conteúdo, além de resolver o tipo do conteúdo, voce deverá informar qual o conteúdo, seja, uma palavra especifica do momento ou um resultado de cálculo ou balanço.

No meu sistema em DOS eu tinha um errorsys com estas características, montei com trechos do livro de Rick Spence e José Ramalho. Ficou uma maravilha, pois me serviu de base para montar rotinas em volta para fazer as manutenções que eu deveria fazer a base do dBase.

Não tente compilar os códigos que postei, mas sim, inxerte partes dele em seu errorsys ou use os errorsys propostos pelos colegas.

Algum irá te servir ou pelo menos te ajudar.

Mas não use esta pratica como parte integrante do sistema. O bom mesmo é que as mensagens de erro nem apresente-se ao usuário como os famosos dialogos telas vermelhas e sim de forma mais simples invocando um suporte seu.