ADO: Perdendo conexão

Fórum sobre Banco de Dados e RDDs para Clipper/[x]Harbour.

Moderador: Moderadores

cjp
Usuário Nível 6
Usuário Nível 6
Mensagens: 1563
Registrado em: 19 Nov 2010 22:29
Localização: paraná
Contato:

ADO: Perdendo conexão

Mensagem por cjp »

Pessoal, a linha oRs:requery(), da qual tratamos aqui, eu acresci em uma outra função do meu sistema. E, nessa outra função, está dando o seguinte erro:
Error WINOLE/1007 [ma-3.1.6][5.6.49-log]MySQL server has gone away (0x80004005): Microsoft OLE DB Provider for ODBC Drivers
Não é uma vez ou outra. Nessa função, sempre ocorre este erro.

Estranho, porque na função de que tratamos aqui neste post, a requery() funciona bem.

A função onde está dando erro está assim:

Código: Selecionar todos

	  elseif nkey == -18
	         nVez++
		     chmfunc("veronus",,"S")
			 if nVez>5
		        keyb chr(27)
			 else
		        oRs:requery()
			 endif
Pensei ser erro na função veronus(), mas não achei nenhum problema nela. Posto aqui para quem quiser conferir:

Código: Selecionar todos

function veronus
         local nrserv :=3
		 local cProc, nronus
		 local tpon :=0
		 private conexao2
		 
         cadativ("Veronus","Veronus: início"," ",0," ",0,0," ")
		 
         IF ADOconecta( nrserv, 3, 2 )
            cProc := conexao2:Execute( "SELECT numero,tempo FROM onus WHERE usuario='"+us+"' AND resolvido<>'S' AND data='"+dtsql(date())+"'" )
			if cProc:recordcount()=0
               cadativ("Veronus","Não tem ônus"," ",0," ",0,0," ")
			   return .f.
			endif
	        tpon=cProc:Fields("tempo"):Value
		    nronus=cProc:Fields("numero"):Value
            cProc:Close()
            conexao2:Close()
			
            hrintar=hrintar+tpon
			
            exqado("UPDATE onus SET resolvido='S' WHERE numero="+alltrim(str(nronus)),nrserv)
			
            cadativ("Veronus","Veronus pegou ônus de "+alltrim(str(tpon))+" e aumentou o hrintar para "+alltrim(str(hrintar))," ",0," ",0,0," ")
		 endif
		 
		 nHrInicAtiv=nHrInicAtiv+tpon+5
return .t.


Alguém saberia me dizer qual a razão desse erro?
Inacio de Carvalho Neto
alxsts
Colaborador
Colaborador
Mensagens: 3092
Registrado em: 12 Ago 2008 15:50
Localização: São Paulo-SP-Brasil

tbrowse: atualização da tela

Mensagem por alxsts »

Olá!

Na função veronus você fecha a conexão. Quando ela retorna você faz um requery com a conexão fechada. Como quer que funcione?
[]´s
Alexandre Santos (AlxSts)
cjp
Usuário Nível 6
Usuário Nível 6
Mensagens: 1563
Registrado em: 19 Nov 2010 22:29
Localização: paraná
Contato:

tbrowse: atualização da tela

Mensagem por cjp »

Mas eu fecho conexao2, não oRs. São conexões diferentes, e inclusive com tabelas diferentes. Não está certo assim? Ou não dá pra fazer duas conexões diferentes?
Inacio de Carvalho Neto
alxsts
Colaborador
Colaborador
Mensagens: 3092
Registrado em: 12 Ago 2008 15:50
Localização: São Paulo-SP-Brasil

tbrowse: atualização da tela

Mensagem por alxsts »

Olá!

O código não está completo e é confuso. Então, não é possível ver muita coisa...
cjp escreveu:MySQL server has gone away (0x80004005):
Uma coisa é certa: o banco de dados está desconectado. A mensagem é clara. Só não sabemos em que linha o erro ocorreu.
cjp escreveu:Mas eu fecho conexao2, não oRs
Você fecha conexao2 mas, em seguida executa

Código: Selecionar todos

exqado("UPDATE onus SET resolvido='S' WHERE numero="+alltrim(str(nronus)),nrserv)
Não se sabe em que conexão é feito isto mas, se for conexao2, ela está fechada. Verifique. Pode estar aí o problema...
cjp escreveu:Ou não dá pra fazer duas conexões diferentes?
Sim, é possível. Normalmente se usa esta técnica para conectar a dois servidores diferentes. Em um mesmo servidor, normalmente não é necessário.
[]´s
Alexandre Santos (AlxSts)
cjp
Usuário Nível 6
Usuário Nível 6
Mensagens: 1563
Registrado em: 19 Nov 2010 22:29
Localização: paraná
Contato:

tbrowse: atualização da tela

Mensagem por cjp »

É o mesmo servidor. Só são tabelas diferentes.
Realmente eu poderia fazer na mesma conexão sem fechar, não tinha pensado nisso.
A linha que vc questionou (exqado("UPDATE onus SET resolvido='S' WHERE numero="+alltrim(str(nronus)),nrserv)) executa outra conexão. Vou verificar se por acaso não é ela que está fechando a conexão anterior, mas acho que não. Já posto.
Inacio de Carvalho Neto
cjp
Usuário Nível 6
Usuário Nível 6
Mensagens: 1563
Registrado em: 19 Nov 2010 22:29
Localização: paraná
Contato:

tbrowse: atualização da tela

Mensagem por cjp »

Confirmei que a exqado executa outra conexão, e não fecha a conexão que está dando problema.
Inacio de Carvalho Neto
alxsts
Colaborador
Colaborador
Mensagens: 3092
Registrado em: 12 Ago 2008 15:50
Localização: São Paulo-SP-Brasil

tbrowse: atualização da tela

Mensagem por alxsts »

Olá!
cjp escreveu:Confirmei que a exqado executa outra conexão, e não fecha a conexão que está dando problema.
Que bom! O código completo está em tuas mãos. Revise tudo e certamente vai encontrar o problema. Agora é com você. Boa sorte!
[]´s
Alexandre Santos (AlxSts)
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

tbrowse: atualização da tela

Mensagem por JoséQuintas »

ado.png
NÃO É PRA COPIAR.

Com certeza, cnSQL é uma conexão, e cnInternet é outra.
No seu fonte, o que é o que? Dá pra ver? Como dizer se está certo ou errado?

Qual o problema?
Pode ser que caiu a conexão, pode ser que está usando ODBC errado, pode ser que o Windows está derrubando, pode ser fonte errado que não se vê, pode ser qualquer coisa.
Vai ter que olhar com muita atenção o que suas rotinas fazem, porque o trecho postado não diz nada.

o browse genérico da outra vez deveria ser um ponto de referência pra fazer outras coisas.

Variáveis PRIVATE?
VIXE... piorou.

Código: Selecionar todos

       private conexao2
         cadativ("Veronus","Veronus: início"," ",0," ",0,0," ")
         IF ADOconecta( nrserv, 3, 2 )
            cProc := conexao2:Execute( "SELECT numero,tempo FROM onus WHERE usuario='"+us+"' AND resolvido<>'S' AND data='"+dtsql(date())+"'" )
É criada a variável conexao2, e é executado um comando nessa variável vazia.
Não é vazia?
Ahhh tá... não sei o que, não sei aonde, faz não sei o que, mas não funciona. qual é o problema? deve ser não sei o que não sei aonde.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
alxsts
Colaborador
Colaborador
Mensagens: 3092
Registrado em: 12 Ago 2008 15:50
Localização: São Paulo-SP-Brasil

tbrowse: atualização da tela

Mensagem por alxsts »

Olá!
JoséQuintas escreveu:Com certeza, cnSQL é uma conexão, e cnInternet é outra.
Neste caso, cnInternet parece ser um ADO RecordSet. O Objeto connection não tem a propriedade Eof...
[]´s
Alexandre Santos (AlxSts)
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

tbrowse: atualização da tela

Mensagem por JoséQuintas »

Foi só pra exemplo.
Minha classe junta tudo numa coisa só, pra facilitar e acrescentar extras.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
cjp
Usuário Nível 6
Usuário Nível 6
Mensagens: 1563
Registrado em: 19 Nov 2010 22:29
Localização: paraná
Contato:

tbrowse: atualização da tela

Mensagem por cjp »

A minha função genérica está assim:

Código: Selecionar todos

FUNCTION TBrowseADO( oRsBrAdo, aCamposList, bExecutaRotinaUsuario )
   LOCAL oBrowse, nKey
   
   SuperADO( oRsBrAdo )
   
   oBrowse := CriaBrowse( oRsBrAdo, aCamposList )

   DO WHILE .T.
      oBrowse:refreshCurrent()
      DO WHILE ! oBrowse:Stable()
         oBrowse:Stabilize()
      ENDDO
      // Paint TBrowse current line...
      //oBrowse:ColorRect( { oBrowse:RowPos, oBrowse:LeftVisible, oBrowse:RowPos, oBrowse:RightVisible }, { 2, 1 } )


      if us="I"
         nKey := Inkey(300)
	  else
	     nKey := Inkey(100)
	  endif
	  
      IF nKey == 0
	     if us="I"
            KEYBOARD Chr( K_ESC )
            nKey := Inkey(0)
		 else
            KEYBOARD -18
		 endif
      ENDIF    
	  
      IF oBrowse:applyKey( nKey ) == TBR_EXIT
         EXIT
      ENDIF
      IF bExecutaRotinaUsuario != NIL
         DO WHILE ! oBrowse:Stable
            oBrowse:Stabilize()
         ENDDO
		 
         Eval( bExecutaRotinaUsuario, oBrowse, nKey )
         oBrowse:RefreshAll()
      ENDIF
   ENDDO
RETURN Nil

STATIC FUNCTION CriaBrowse( oRsBrAdo, aCamposList )
   LOCAL oBrowse, oColumn, aItem, nLen, nCont

   if procname(2)="BROWSEITEM"
      oBrowse := TBrowse():new( 07, 1, MaxRow() - 5, MaxCol() - 1 )
   else
      oBrowse := TBrowse():new( 02, 3, MaxRow() - 3, MaxCol() - 3 )
   endif
   
   oBrowse:headSep       := Chr(196) + Chr(194) + Chr(196)
   oBrowse:colSep        := " " + Chr(179) + " "
   oBrowse:footSep       := Chr(196) + Chr(193) + Chr(196)
   oBrowse:goTopBlock    := { || oRsBrAdo:moveFirst() }
   oBrowse:goBottomBlock := { || oRsBrAdo:moveLast() }
   oBrowse:skipBlock     := { |n| ADORecordSetSkipper( oRsBrAdo,n ) }
   
   if us#"I" .and. (procname(1)="ENTERITEM" .or. procname(2)="ENTERITEM" .or. procname(3)="ENTERITEM" .or. procname(4)="ENTERITEM" .or. procname(5)="ENTERITEM" .or. procname(6)="ENTERITEM" .or. procname(7)="ENTERITEM")
	  keysec(-18,115,-1,.t.)
   else
	  keysec(27,1200,-1,.t.)
   endif
		 
   IF aCamposList == Nil
      nLen := oRsBrAdo:fields():count() - 1
      FOR nCont := 0 TO nLen
         oColumn := TBColumnNew( oRsBrAdo:fields( nCont ):name(), ADORecordSetFieldBlock( oRsBrAdo, nCont ) )
         oColumn:width := Max( Min( oRsBrAdo:Fields( nCont ):definedSize,50), Len( oRsBrAdo:fields( nCont ):name ) ) + 5
         oBrowse:addColumn( oColumn )
      NEXT
   ELSE
      FOR EACH aItem IN aCamposList
         oColumn := TBColumnNew( aItem[1], aItem[2] )
         IF Len( aItem ) > 2
            oColumn:ColorBlock := aItem[3]
         ENDIF
         oBrowse:AddColumn( oColumn )
      NEXT
   ENDIF
RETURN oBrowse

FUNCTION SuperADO( oRsBrAdo )
   __ObjAddMethod( oRsBrAdo, "TOSTRING", @ADOToString() )
   __ObjAddMethod( oRsBrAdo, "TONUMBER", @ADOToNumber() )
   __ObjAddMethod( oRsBrAdo, "TODATE",   @ADOToDate() )
   __ObjAddMethod( oRsBrAdo, "TOSTR",    @ADOToStr() )

RETURN Nil

STATIC FUNCTION ADOToDate( cField )
   LOCAL x, Self := QSelf()

   x := ::Fields( cField ):Value
   IF ValType( x ) != "D"
      x := Ctod("")
   ENDIF
RETURN x

STATIC FUNCTION ADOToString( cField, nLen )
   LOCAL x, Self := QSelf()

   x := ::Fields( cField ):Value
   IF ValType( x ) != "C"
      x := ""
   ENDIF
   IF nLen != Nil
      x := Pad( x, nLen )
   ENDIF
RETURN x

STATIC FUNCTION ADOToNumber( cField )
   LOCAL x, Self := QSelf()

   x := ::Fields( cField ):Value
   IF ValType( x ) != "N"
      x := 0
   ENDIF
RETURN x

STATIC FUNCTION ADOToStr( cField, nLen, nDec )
   LOCAL x, Self := QSelf()

   x := ::Fields( cField ):Value
   IF ValType( x ) != "N"
      x := 0
   ENDIF
   IF nLen == Nil
      x := Str( x )
   ELSEIF nDec == Nil
      x := Str( x, nLen )
   ELSE
      x := Str( x, nLen, nDec )
   ENDIF
RETURN x

FUNCTION ConexaoMySQL( cServer, cDatabase, cUser, cPassword )
       LOCAL oCn := win_OleCreateObject("ADODB.Connection")

       oCn:ConnectionString := "DRIVER={MariaDB ODBC 3.1 Driver};TCPIP=1;SERVER=" + ;
        cServer + ";Database=" + cDatabase + ";UID=" + cUser + ";PWD=" + cPassword + ";PORT=3306"
       oCn:CursorLocation   := 3
RETURN oCn

Alterei oRs para oRsBrAdo para não ter a menor chance de ela ser alterada em nenhuma outra parte do sistema.

Na função de usuário tem também:
LOCAL oCnBrAdo :=ConexaoMySQL( "mysql.meuprovedor.com.br", "xxx", "xxx", "senha" )
A variável conexao2 está como private porque a Adoconecta usa ela, assim:

Código: Selecionar todos

function ADOconecta(nProvedor,nTentativas,nConexao)
         local vez :=0
		 local cRet :="F"
		 
		 nTentativas=2  // para diminuir tentativas quando não tiver conexão
		 
         bError := ErrorBlock( {|e| Break(e) } )
         begin sequence
		       if nProvedor=NIL
		          nProvedor=3
		       endif
		 
		       if nTentativas=NIL
		          nTentativas=3
		       endif
		 
         recover using e
                 cMessage := ErrorMessage(e)
                 logerro()
                 mandmail1("error.log","Erro na ADOconnecta1 contornado com o recover do begin sequence")
         endsequence
         ErrorBlock( bError )
		 
         do while .t.
		 
            bError := ErrorBlock( {|e| Break(e) } )
            begin sequence
		 
		          vez++
			      if vez>1
			         @ maxrow()-1,1 say "Tentando conexão com o servidor "+alltrim(str(nProvedor))+" ("+alltrim(str(vez))+"/"+alltrim(str(nTentativas+1))+")"
			         inkey(5.1)
			      endif
			
            recover using e
                    cMessage := ErrorMessage(e)
                    logerro()
                    mandmail1("error.log","Erro na ADOconnecta2 contornado com o recover do begin sequence")
            endsequence
            ErrorBlock( bError )
		 
			if vez>nTentativas
			   if nProvedor=12 .or. nProvedor=1 //.and. ("AGENDA"$Hb_CmdArgArgV() .or. "PROCESSO"$Hb_CmdArgArgV())
				  mandmail1("","Mudou nProvAtiv para 3 na ADOconecta porque não funcionou no "+alltrim(str(nProvedor)))
			      nProvAtiv=3
			   endif
			   return .f.
			endif
			
            bError := ErrorBlock( {|e| Break(e) } )
            begin sequence
		 
                  if nConexao=2
				     conexao2 := conexADO(nProvedor)
				  else
				     conexao := conexADO(nProvedor)
			      endif
			
            recover using e
                    cMessage := ErrorMessage(e)
                    logerro()
                    mandmail1("error.log","Erro na ADOconnecta3 contornado com o recover do begin sequence")
            endsequence
            ErrorBlock( bError )
			
            bError := ErrorBlock( {|e| Break(e) } )
            begin sequence
                  IF (nConexao=2 .and. AbreADO(conexao2)) .or. AbreADO( conexao )
			         if vez>1
			            @ maxrow()-1,1 clear to maxrow()-1,40
			         endif
			         cRet="T"
			      Endif
            recover using e
                    cMessage := ErrorMessage(e)
                    logerro()
                    mandmail1("error.log","Erro na ADOconnecta4 contornado com o recover do begin sequence")
            endsequence
            ErrorBlock( bError )
			
			if cRet="T"
			   return .t.
			endif
			
		 enddo
return .t.
Talvez dê para melhorar isso.
Mas, ao que me parece (me corrija se eu estiver errado), nem a veronus() nem a adoconecta() está encerrando a conexão do browse.
Eu não creio que o problema seja queda de conexão, ou ODBC errado, ou Windows derrubando, pois o problema tem ocorrido somente neste ponto do sistema, e sempre no mesmo ponto. Além disso, só passou a dar este problema depois que eu mudei para este browse genérico (quando eu uso o meu browse anterior, aquele confuso, não ocorre o problema).
Consegue dar uma luz de onde eu poderia procurar o problema? Aqui não estou enxergando nada.
Inacio de Carvalho Neto
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

tbrowse: atualização da tela

Mensagem por JoséQuintas »

Compilação -w3 -es2, evitar private.....

Código: Selecionar todos

   private conexao2
   cadativ("Veronus","Veronus: início"," ",0," ",0,0," ")
   IF ADOconecta( nrserv, 3, 2 )
...
function ADOconecta(nProvedor,nTentativas,nConexao)
que tal assim?

Código: Selecionar todos

LOCAL conexao2
IF ADOConecta( nServ, 3, 2, @Conexao2 )
...
function ADOconecta(nProvedor,nTentativas,nConexao, @oQualquerNome)
E lá voltamos a falar sobre usar variável PRIVATE, sobre deixar função presa com variável que não é dela, etc. etc. etc.
Mesmo assunto, mesma coisa, em outra função.

Função é... função. Tem que ser independente.

Usa no aplicativo inteiro... o aplicativo inteiro depende disso... e isso usa não se sabe o que, que vém e vai não se sabe onde.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

tbrowse: atualização da tela

Mensagem por JoséQuintas »

Antes que digam..... parece o mesmo.... mas é totalmente diferente.

Na primeira rotina Conexao2 nasce ali, e morre ali, e só é visível ali.

Na função, ela recebe uma variável e retorna preenchida. sabe-se que veio como parâmetro e volta exatamente para o mesmo lugar de onde veio.
Ainda não é o ideal, mas já melhora muuuito.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

tbrowse: atualização da tela

Mensagem por JoséQuintas »

cjp escreveu:Alterei oRs para oRsBrAdo para não ter a menor chance de ela ser alterada em nenhuma outra parte do sistema.
Só veio na cabeça: Put. que par....

ISSO É VARIÁVEL LOCAL.

Pode alterar os raios que o partam no aplicativo inteiro, que isso NUNCA vai mudar.

Faça a comprovação:

Código: Selecionar todos

PROCEDURE Main

   LOCAL A

   a := "5"
   ? "main " + a
   Funcao( a )
   ? "main " + a
   Inkey(0)
   RETURN

FUNCTION FUNCAO( a )

   a := "10"
   ? "funcao " + a
   RETURN Nil
É justamente essa a diferença entre variável PRIVATE e LOCAL, e é por isso que variável LOCAL é o que tem de melhor.

Se está pensando que vai mostrar 5, 10, 10..... está ERRADO.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

tbrowse: atualização da tela

Mensagem por JoséQuintas »

Vamos um pouco mais:

Quer que mostre 5, 10, 5 é do jeito que está aí.

Quer que mostre 5, 10, 10 então é funcao( @a )

E tanto faz o nome da variável dentro da função, o resultado vai ser sempre o mesmo acima.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Responder