Página 1 de 1

Rotina de Auditoria para SGBD

Enviado: 26 Fev 2020 08:34
por asimoes
Pessoal,

Estou migrando para um SGDB, escolhi o MariaDb, no momento usando o ADS da SYBASE como ponte na construção das query´s, tenho uma função de auditora de dados no DBF, onde comparo os campos do registro atual com o modificado, como fazer isso agora ?

Rotina de Auditoria para SGBD

Enviado: 26 Fev 2020 09:47
por JoséQuintas
Sugestão:

Toda tabela tem uma chave.
cria uma rotina pra pegar o registro e comparar.

Uma primeira rotina salva num array
Uma segunda rotina comparara esse array com o array atual.

Registro:Salva( "tabela", "chave" )

atualiza

Registro:Compara( "tabela", "chave" )

Rotina de Auditoria para SGBD

Enviado: 26 Fev 2020 10:30
por alxsts
Olá!

Use triggers...

Rotina de Auditoria para SGBD

Enviado: 26 Fev 2020 13:16
por asimoes
alxsts escreveu:Olá!

Use triggers...
Ainda não migrei para o MariaDb, estou na fase de troca de sintaxe paa acessar o dbf, via sql

Quintas tens algum exemplo ?

Rotina de Auditoria para SGBD

Enviado: 26 Fev 2020 13:23
por asimoes
JoséQuintas escreveu:Sugestão:

Toda tabela tem uma chave.
cria uma rotina pra pegar o registro e comparar.

Uma primeira rotina salva num array
Uma segunda rotina comparara esse array com o array atual.

Registro:Salva( "tabela", "chave" )

atualiza

Registro:Compara( "tabela", "chave" )
Tenho uma rotina que é uma grid onde e o usuário pode excluir qq linha dessa grid que persiste no dbf, antes de auditar faço um set deleted off pra poder pegar o registro deletado, depois faço set deleted on, acontece que com o ads não tem isso, não funciona o set deleted off pra poder pegar o deleted do dbf

Rotina de Auditoria para SGBD

Enviado: 26 Fev 2020 13:37
por JoséQuintas
ainda estou adaptando, mas de um modo geral é salvar no array.

Código: Selecionar todos

CREATE CLASS ADORecValueClass

   VAR aValues

   METHOD New( cnMySql )
   METHOD WriteLog( cTable, cKeyName, xKeyValue )

   ENDCLASS

METHOD New( cnMySql ) CLASS ADORecValueClass

   LOCAL nCont

   ::aValues := {}
   IF cnMySql != NIL
      WITH OBJECT cnMySql
         FOR nCont = 1 TO :FCount()
            AAdd( ::aValues, :String( nCont - 1 ) )
         NEXT
      ENDWITH
   ENDIF

   RETURN SELF

METHOD WriteLog( cTable, cKeyName, xKeyValue ) CLASS ADORecValueClass

   LOCAL nCont, cnMySql := ADOClass():New( AppConexao() )

   IF AppConexao() == NIL
      RETURN NIL
   ENDIF
   WITH OBJECT cnMySql
      :cSql := "SELECT * FROM " + cTable + " WHERE " + cKeyName + " = " + NumberSql( xKeyValue )
      :Execute()
      IF ! :Eof()
         FOR nCont = 1 TO :FCount()
            IF ! "INFINC" $ :FName( nCont - 1 ) .AND. ! "INFALT" $ :FName( nCont - 1 ) ;
               .AND. ! ::aValues[ nCont ] == :String( nCont - 1 )
               GravaOcorrencia( cTable, StrZero( xKeyValue, 9 ), "ALTERADO " + :FName( nCont - 1 ) + ;
                  " de " + Transform( ::aValues[ nCont ], "" ) + ;
                  " para " + :String( nCont - 1 ) )
            ENDIF
         NEXT
      ENDIF
      :CloseRecordset()
   ENDWITH

   RETURN NIL

   // Alterado pra usar com MySQL a partir de DBF

CREATE CLASS DBFRecValueClass

   VAR  aValues

   METHOD WriteLog( xTable, xKey )
   METHOD Init()

   ENDCLASS

METHOD Init() CLASS DBFRecValueClass

   LOCAL nCont

   ::aValues := {}
   FOR nCont = 1 TO FCount()
      Aadd( ::aValues, FieldGet( nCont ) )
   NEXT

   RETURN NIL

METHOD WriteLog( xTable, xKey ) CLASS DBFRecValueClass

   LOCAL cAlias, cCodigo, nCont, cTexto

   IF ! xTable == NIL .AND. ! xKey == NIL
      FOR nCont = 1 TO FCount()
         cTexto := ""
         IF ::aValues[ nCont ] != FieldGet( nCont ) .AND. ! "INFINC" $ FieldName( nCont ) .AND. ! "INFALT" $ FieldName( nCont )
            cTexto += FieldName( nCont ) + " DE " + Trim( Transform( ::aValues[ nCont ], "" ) )
            cTexto += " PARA " + Trim( Transform( FieldGet( nCont ), "" ) )
            GravaOcorrencia( Upper( xTable ), xKey, cTexto )
         ENDIF
      NEXT
      RETURN NIL
   ENDIF

   cAlias := Lower( Alias() )
   DO CASE
   CASE cAlias == "jpcadastro" ; cCodigo := jpcadastro->idCadastro
   CASE cAlias == "jpfinan"    ; cCodigo := jpfinan->idFinan
   CASE cAlias == "jpitem"     ; cCodigo := jpitem->idProduto
   CASE cAlias == "jppedido"   ; cCodigo := jppedido->idPedido
   OTHERWISE
      cCodigo := ""
   ENDCASE
   IF Empty( cCodigo )
      RETURN NIL
   ENDIF
   FOR nCont = 1 TO FCount()
      cTexto := ""
      IF ::aValues[ nCont ] != FieldGet( nCont ) .AND. ! "INFINC" $ FieldName( nCont ) .AND. ! "INFALT" $ FieldName( nCont )
         cTexto += FieldName( nCont ) + " DE " + Trim( Transform( ::aValues[ nCont ], "" ) )
      ENDIF
      IF ! Empty( cTexto )
         GravaOcorrencia( Upper( Alias() ), cCodigo , cTexto )
      ENDIF
   NEXT

   RETURN NIL
Tenho em cada registro o INFINC e INFALT que é data de inclusão/alteração, então não comparo no log, senão sempre iria gravar.
Mas é como eu falei: cria um array antes, e compara com o array depois.

Rotina de Auditoria para SGBD

Enviado: 26 Fev 2020 13:41
por JoséQuintas
Em DBF:

oRec := DBFRecValuesClass():New()
REPLACE .....
oRec:WriteLog( Alias(), chave )

No log vai registrar a tabela, a chave, e o que mudou.

Em ADO... aproveito o SELECT * que pega o registro atual... e passo a tabela/chave para a rotina buscar no MySQL depois.
Pensando em usar tabela/chave nos dois casos.

Uso isso também pra ter as "ocorrências" individuais.
Por exemplo: vai lá no cadastro de clientes número 10, e vê o histórico de tudo que foi alterado nele, só precisa da tabela e chave pra isso.

No log geral vê tudo.
No log do cliente, só vê o que tá como "cliente", código "10"
Simples e prático.

Rotina de Auditoria para SGBD

Enviado: 26 Fev 2020 13:51
por JoséQuintas
asimoes escreveu:acontece que com o ads não tem isso, não funciona o set deleted off pra poder pegar o deleted do dbf
Até tem, mas não faço idéia de como faria o SELECT para os deletados.
Isso fica na string de conexão, e poderia ter uma conexão para os deletados.

Rotina de Auditoria para SGBD

Enviado: 26 Fev 2020 16:09
por asimoes
JoséQuintas escreveu:Até tem, mas não faço idéia de como faria o SELECT para os deletados.
Isso fica na string de conexão, e poderia ter uma conexão para os deletados.
No MaySql, Oracle ou MariaDb, o delete from table, não tem como ver, o registro é seguido de um "pack" se errou ferrou!, por isso essas coisas tem que estar dentro de um controle de transação begintrans(), CommitTrans() e RollBackTrans() o driver OleDb da Ads não tem isso.

Rotina de Auditoria para SGBD

Enviado: 26 Fev 2020 18:39
por alxsts
Olá!
asimoes escreveu:No MaySql, Oracle ou MariaDb, o delete from table, não tem como ver, o registro é seguido de um "pack" se errou ferrou!
alxsts escreveu:Use triggers...
Toda vez que um trigger é disparado, tem-se acesso à situação atual do registro e a situação futura (imagens OLD e NEW, também conhecidos como "before image" e "after image"). Um trigger pode ser disparado antes ou depois de um INSERT, UPDATE ou DELETE. É só tratar a situação conforme a necessidade.

What is a Trigger? (ADS)

Writing Triggers in SQL (ADS)

Trigger Overview MariaDB

Rotina de Auditoria para SGBD

Enviado: 26 Fev 2020 19:21
por asimoes
Não faço a minima ideia como fazer uso de trigger do ads