Ver Mensaje Individual
  #17  
Antiguo 07-04-2011
Avatar de fjcg02
[fjcg02] fjcg02 is offline
Miembro Premium
 
Registrado: dic 2003
Ubicación: Zamudio
Posts: 1.410
Reputación: 22
fjcg02 Va camino a la fama
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
  /* triggers de AUDITORIA
     Primero borra todos los triggers de auditoria actuales.
  Se deben llamar todos DYPE_AUDIT% */
  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

  /* Se recrean todos los triggers necesarios.
    ATENCION! Todas las tablas deben tener un campo de clave primaria y
    este campo debe seguir el patron IDNOMBRETABLA */
  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
    /* Crea el trigger de auditoria */
    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;
__________________
Cuando los grillos cantan, es que es de noche - viejo proverbio chino -
Responder Con Cita