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