Documente Academic
Documente Profesional
Documente Cultură
es/2016/08/como-auditar-cambios-usando-triggers-
en.html
Se nos ha planteado la posibilidad que indicar quién y qué es lo que se cambia en una serie de
tablas.
Sabía desde hace tiempo que el driver rdd de sixdrive permite introducir un trigger para
controlar el contenido.
Pero nosotros usamos DBFNTX, y no podemos cambiar así como así el sistema de RDD.
Por suerte para nosotros, la gente de Harbour le dio soporte también a los NTX.
Hemos diseñado un sistema de tablas, log y logid, que determina que tablas hacermos logs, y
el campo de la PK, para encontrar los cambios de un registro de una tabla determinada.
Después , tenemos otra tabla LOGID, que determinará que TABLA vamos a auditar, en este
caso, tenemos una especie de DBU integrado que necesitamos control de todas las tablas,
porque como veremos , simplemente se activa en la apertura de la tabla si queremos que se
disparen los triggers o no,y cual es el campo de la tabla que queremos que se guarde en el
ID_VALUE de la tabla LOG.
También, en el ejemplo, evito introducir los nuevos registros, y los campos que sean iguales,
tampoco se guardarán. Esto programarlo como queráis, la imaginación es solamente vuestra
meta ;-)
Despues, si estamos en un cliente, por ejemplo , donde la PK es el DNI y usamos el DNI como
ID a la hora de guardar el log, simplemente haciendo un SCOPE de la tabla + el DNI del
cliente, obtendremos todos los cambios aplicados a ese registro ;-)
Este ejemplo lo podéis ejecutar en el directorio de \harbour\tests, y usa la tabla test.dbf con
hbmk2 trigger.prg hbct.hbc xhb.hbc
#include "Hblog.ch"
#include "dbinfo.ch"
#include "hbsix.ch"
//REQUEST DBFNTX
Function Main()
setmode( 25,80 )
/* Activa log */
INIT LOG FILE( NIL, "audit.log", 1000, 999 ) // Tamaño a 100K y
maximo 999 ficheros
LOG "Ejemplo de auditar cambios a traves de triggers."
/* Activar triggers*/
rddInfo( RDDI_TRIGGER, "SX_DEFTRIGGER", "DBFNTX" )
Select TEST
go top
if rlock()
replace FIRST with alltrim( field->FIRST ) + "_TEST"
unlock
commit
endif
Select TEST2
go bottom
if rlock()
replace LAST with alltrim( field->LAST ) + "_TEST"
replace NOTES with "Changes everything"
unlock
endif
CLOSE LOG
CLOSE ALL
Return 0
function _trigger( nEvent, nArea, nFieldPos, xTrigVal )
Local xIdValue, xValue, cIdValue
DO CASE
if xTrigVal != xValue
xIdValue := cValtoChar( &( cIdValue ) )
if !empty( xIdValue ) // Si hay algún valor, se
guarda, en registros nuevos, el valor esta vacio, no hay que dejar
log
LOG " TABLE:" + ALIAS( nArea ) +;
" FIELD:" + (nArea)-
>( FieldName( nFieldPos ) ) +;
" ID VALUE:" + xIdValue +;
" OLD VALUE:" + alltrim( cValtoChar( (nArea)-
>( FieldGet( nFieldPos ) ) ) ) +;
" NEW VALUE:" +
alltrim( cValtoChar( xTrigVal ) )+;
" DATETIME:" + hb_ttos( hb_datetime() ) +;
" HOSTNAME:" + netname()
endif
endif
sx_SetTrigger( TRIGGER_ENABLE )
Return( .T. )
/*
Devuelve el ID a usar segun la tabla.
hLogId es un hash que contiene la tabla y el valor de una
expresion de esa tabla que usaremos
para identificar el registro en el log.
Generalmente, se debe usar un PK, una clave única.
*/
static function __GetIdLog( cTable )
Local cId
static hLogId := { "TEST" => "FIRST + LAST", "TEST2" =>
"SALARY"}
return cId