Hola,
despues de andar buscando por ahi, he encontrado este codigo que puede servir a alguien. No sé de dónde lo he sacado, para al menos mencionar a su autor.
Se basa en la creación de dos triggers por tabla. Toda la información de auditoria de todas las tablas queda almacenada en la misma tabla.
Es fácil hacer una función desde el programa delphi que muestre todos los cambios que ha sufrido un registro a lo largo de su vida.
Cuando se modifican las tablas, hay que ejecutarlo para actualizar los triggers
Espero que le sirva a alguien
Saludos
Código SQL
[-]*******************************************************
Este procedimiento sirve para crear triggers de auditoria para todas las tablas
La primera vez que se ejecuta, se crean todas los triggers.
La segunda vez que se ejecuta, se borran todos los trigrers
Se usa la sentencia "execute statement" en la procedure para borrar/crear los triggers
-- script
DECLARE EXTERNAL FUNCTION ASCII_CHAR
INTEGER
RETURNS CSTRING(1) FREE_IT
ENTRY_POINT 'IB_UDF_ascii_char' MODULE_NAME 'ib_udf';
CREATE GENERATOR AUDITORIA;
create domain DN_KEY as integer;
create domain DN_DESCRIPTION as varchar(255);
create domain DN_DATE as date;
create domain DN_TIME as time;
create domain DN_DOCNUMBER as varchar(20);
create domain DN_BLOB as BLOB sub_type 0 SEGMENT SIZE 80;
CREATE TABLE AUDITORIA (
IDAUDITORIA DN_KEY NOT NULL,
IDEJECUTOR DN_KEY NOT NULL,
IDPERFIL DN_KEY NOT NULL,
IDOBJETO DN_KEY NOT NULL,
OBJETO DN_DESCRIPTION NOT NULL,
FECHA DN_DATE NOT NULL,
HORA DN_TIME NOT NULL,
ACCION DN_DOCNUMBER NOT NULL,
CAMPO DN_DESCRIPTION NOT NULL,
"OLD" DN_BLOB,
"NEW" DN_BLOB,
DESCRIPCION DN_BLOB
);
alter table AUDITORIA add constraint PK_AUDITORIA primary key (IDAUDITORIA);
create index IDX_AUDIT_OBJETO on AUDITORIA (IDOBJETO);
CREATE OR ALTER TRIGGER AUDITORIA_BI FOR AUDITORIA
ACTIVE BEFORE INSERT POSITION 0
as
begin
if (new.IDAUDITORIA is null) then
new.IDAUDITORIA = gen_id(AUDITORIA, 1);
if (new.IDEJECUTOR is null) then
new.IDEJECUTOR = 1;
if (new.IDPERFIL is null) then
new.IDPERFIL = 2;
new.FECHA = current_date;
new.HORA = current_time;
end;
CREATE OR ALTER PROCEDURE AUDITORIA_REBUILD_TRIGGERS
RETURNS (
DESCRIPCION VARCHAR(32000))
AS
declare variable TABLA varchar(255);
declare variable COLUMNA varchar(255);
declare variable COLUMNA_TIPO varchar(255);
declare variable TRIGGERNAME varchar(255);
begin
for select
trim(T.RDB$TRIGGER_NAME)
from
RDB$TRIGGERS T
where
T.RDB$TRIGGER_NAME like 'DYPE_AUDIT%'
into
:TRIGGERNAME
do
begin
execute statement 'drop trigger ' || TRIGGERNAME;
DESCRIPCION = 'droped trigger ' || TRIGGERNAME;
suspend;
end
for select
trim(R.RDB$RELATION_NAME)
from
RDB$RELATIONS R
where
R.RDB$SYSTEM_FLAG = 0 and
R.RDB$VIEW_BLR is null and
-- aqui se relacionan las tablas que no queremos que borre/añadan triggers
R.RDB$RELATION_NAME not in ('AUDITORIA', 'TABLAXXX') and
( select
count(*)
from
RDB$RELATION_CONSTRAINTS RC inner join
RDB$INDEX_SEGMENTS ISPK on ISPK.RDB$INDEX_NAME = RC.RDB$INDEX_NAME
where
RC.RDB$CONSTRAINT_TYPE = 'PRIMARY KEY' and
RC.RDB$RELATION_NAME = R.RDB$RELATION_NAME
group by
RC.RDB$RELATION_NAME
) = 1
into
:TABLA
do
begin
DESCRIPCION = 'create trigger DYPE_AUDIT_' || substring(TABLA from 1 for 20) || ' for ' || TABLA || ASCII_CHAR(13) || ASCII_CHAR(10) ||
'active AFTER INSERT or UPDATE or DELETE position 1' || ASCII_CHAR(13) || ASCII_CHAR(10) ||
'as' || ASCII_CHAR(13) || ASCII_CHAR(10) ||
'begin' || ASCII_CHAR(13) || ASCII_CHAR(10) ||
' /* Trigger generado automaticamente para mantener laa auditoria */' || ASCII_CHAR(13) || ASCII_CHAR(10) ||
' if (inserting) then' || ASCII_CHAR(13) || ASCII_CHAR(10) ||
' begin' || ASCII_CHAR(13) || ASCII_CHAR(10);
for select
trim(RF.RDB$FIELD_NAME),
trim(T.RDB$TYPE_NAME)
from
RDB$RELATION_FIELDS RF inner join
RDB$FIELDS F on F.RDB$FIELD_NAME = RF.RDB$FIELD_SOURCE inner join
RDB$TYPES T on T.RDB$TYPE = F.RDB$FIELD_TYPE and T.RDB$FIELD_NAME = 'RDB$FIELD_TYPE'
where
RF.RDB$RELATION_NAME = :TABLA
into
:COLUMNA,
:COLUMNA_TIPO
do
begin
if (COLUMNA_TIPO not in ('BLOB', 'VARYING')) then
DESCRIPCION = DESCRIPCION || ' insert into AUDITORIA (IDOBJETO, OBJETO, ACCION, CAMPO, NEW) values (new.ID' || TABLA || ', ''' || TABLA || ''', ''INSERT'', ''' || COLUMNA || ''', cast(new.' || COLUMNA || ' as varchar(32000)));' || ASCII_CHAR(13) || ASCII_CHAR(10);
else
DESCRIPCION = DESCRIPCION || ' insert into AUDITORIA (IDOBJETO, OBJETO, ACCION, CAMPO, NEW) values (new.ID' || TABLA || ', ''' || TABLA || ''', ''INSERT'', ''' || COLUMNA || ''', new.' || COLUMNA || ');' || ASCII_CHAR(13) || ASCII_CHAR(10);
end
DESCRIPCION = DESCRIPCION || ' end' || ASCII_CHAR(13) || ASCII_CHAR(10) ||
' if (updating) then' || ASCII_CHAR(13) || ASCII_CHAR(10) ||
' begin' || ASCII_CHAR(13) || ASCII_CHAR(10);
for select
trim(RF.RDB$FIELD_NAME),
trim(T.RDB$TYPE_NAME)
from
RDB$RELATION_FIELDS RF inner join
RDB$FIELDS F on F.RDB$FIELD_NAME = RF.RDB$FIELD_SOURCE inner join
RDB$TYPES T on T.RDB$TYPE = F.RDB$FIELD_TYPE and T.RDB$FIELD_NAME = 'RDB$FIELD_TYPE'
where
RF.RDB$RELATION_NAME = :TABLA
into
:COLUMNA,
:COLUMNA_TIPO
do
begin
if (COLUMNA_TIPO not in ('BLOB', 'VARYING')) then
DESCRIPCION = DESCRIPCION || ' if (old.' || COLUMNA || ' is distinct from new.' || COLUMNA || ') then' || ASCII_CHAR(13) || ASCII_CHAR(10) || ' insert into AUDITORIA (IDOBJETO, OBJETO, ACCION, CAMPO, OLD, NEW) values (old.ID' || TABLA || ', ''' || TABLA || ''', ''UPDATE'', ''' || COLUMNA || ''', cast(old.' || COLUMNA || ' as varchar(32000)), cast(new.' || COLUMNA || ' as varchar(32000)));' || ASCII_CHAR(13) || ASCII_CHAR(10);
else
DESCRIPCION = DESCRIPCION || ' if (old.' || COLUMNA || ' is distinct from new.' || COLUMNA || ') then' || ASCII_CHAR(13) || ASCII_CHAR(10) || ' insert into AUDITORIA (IDOBJETO, OBJETO, ACCION, CAMPO, OLD, NEW) values (old.ID' || TABLA || ', ''' || TABLA || ''', ''UPDATE'', ''' || COLUMNA || ''', old.' || COLUMNA || ', new.' || COLUMNA || ');' || ASCII_CHAR(13) || ASCII_CHAR(10);
end
DESCRIPCION = DESCRIPCION || ' end' || ASCII_CHAR(13) || ASCII_CHAR(10) ||
' if (deleting) then ' || ASCII_CHAR(13) || ASCII_CHAR(10) ||
' begin' || ASCII_CHAR(13) || ASCII_CHAR(10);
for select
trim(RF.RDB$FIELD_NAME),
trim(T.RDB$TYPE_NAME)
from
RDB$RELATION_FIELDS RF inner join
RDB$FIELDS F on F.RDB$FIELD_NAME = RF.RDB$FIELD_SOURCE inner join
RDB$TYPES T on T.RDB$TYPE = F.RDB$FIELD_TYPE and T.RDB$FIELD_NAME = 'RDB$FIELD_TYPE'
where
RF.RDB$RELATION_NAME = :TABLA
into
:COLUMNA,
:COLUMNA_TIPO
do
begin
if (COLUMNA_TIPO not in ('BLOB', 'VARYING')) then
DESCRIPCION = DESCRIPCION || ' insert into AUDITORIA (IDOBJETO, OBJETO, ACCION, CAMPO, OLD) values (old.ID' || TABLA || ', ''' || TABLA || ''', ''DELETE'', ''' || COLUMNA || ''', cast(old.' || COLUMNA || ' as varchar(32000)));' || ASCII_CHAR(13) || ASCII_CHAR(10);
else
DESCRIPCION = DESCRIPCION || ' insert into AUDITORIA (IDOBJETO, OBJETO, ACCION, CAMPO, OLD) values (old.ID' || TABLA || ', ''' || TABLA || ''', ''DELETE'', ''' || COLUMNA || ''', old.' || COLUMNA || ');' || ASCII_CHAR(13) || ASCII_CHAR(10);
end
DESCRIPCION = DESCRIPCION || ' end' || ASCII_CHAR(13) || ASCII_CHAR(10) ||
'end';
execute statement DESCRIPCION;
DESCRIPCION = 'created trigger DYPE_AUDIT_' || substring(TABLA from 1 for 20);
suspend;
end
end;