Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Bases de datos > Firebird e Interbase
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 10-03-2010
Avatar de fjcg02
[fjcg02] fjcg02 is offline
Miembro Premium
 
Registrado: dic 2003
Ubicación: Zamudio
Posts: 1.412
Poder: 22
fjcg02 Va camino a la fama
Trigger auditoria

Hola a todos,
estoy intentando hacer un trigger que audite una serie de campos de varias tablas.

Como no quiero estar poniendo el churro de campos de cada tabla, estoy intentando hacer un trigger genérico que me ayude al menos a reutilizar el código.
El problema es que no consigo dar con el problema.

He aquí el código maldito
Código SQL [-]
AS
declare variable WCAMPO varchar(50);
declare variable sentencia varchar(100);
begin
  /* Trigger text */

  FOR SELECT RF.RDB$Field_Name CAMPO  /* Nombre del campo */
      FROM RDB$Relation_Fields RF
      WHERE RF.RDB$Relation_Name = 'TABLA' /* Aqui la tabla del trigger */
      INTO :WCAMPO
  DO
    BEGIN
      sentencia =  'IF (new.'||:WCAMPO ||'IS NOT NULL) THEN '||
       'BEGIN '||
         'IF (OLD.'||:WCAMPO||' <> NEW.'||:WCAMPO||' ) THEN ' ||
           'INSERT INTO AUDITORIA (IDAUDITORIA, FECHA, USUARIO, IDREGISTRO,'||
                                   'TABLA, CAMPO, VALORVIEJO,VALORNUEVO) '||
            'VALUES (GEN_ID(AUDITORIA,1), '||'''NOW'''||', NEW.USUARIOMODIF, NEW.IDPOLIZA,'||
                                 '''POLIZA'','||:WCAMPO||', CAST(OLD.'||:WCAMPO||' AS VARCHAR(50)),CAST( NEW.'||:WCAMPO||' AS VARCHAR(50)) )'';'||
       'END' ;
    END
    execute statement sentencia;

end
Pues eso, que me estoy haciendo la picha un lio.

Debo decir que si hago un store proc. que me devuelva la variable SENTENCIA - que es la que se ejecuta después con el execute statement - y la copio en el ibexpert, me la ejecuta bien

O sea, que estoy enrocado.

Agradecería cualquier ayuda de los maestros.

Gracias y un saludo
__________________
Cuando los grillos cantan, es que es de noche - viejo proverbio chino -
Responder Con Cita
  #2  
Antiguo 10-03-2010
Avatar de fjcg02
[fjcg02] fjcg02 is offline
Miembro Premium
 
Registrado: dic 2003
Ubicación: Zamudio
Posts: 1.412
Poder: 22
fjcg02 Va camino a la fama
VAmos avanzando, ahora se compila bien. Observese que he aumentado el tamaño de la variable sentencia.

Pero a la hora de hacer un cambio en la tabla, me dice que no puede convertir a string un valor - no especifica cual - , pero que tiene que ser el propio valor del campo.

Seguimos a la espera.

Código SQL [-]
AS
declare variable WCAMPO varchar(50);
declare variable sentencia varchar(500);
begin
  /* Trigger text */

  FOR SELECT RF.RDB$Field_Name CAMPO  /* Nombre del campo */
      FROM RDB$Relation_Fields RF
      WHERE RF.RDB$Relation_Name = 'TABLA' /* Aqui la tabla del trigger */
      INTO :WCAMPO
  DO
    BEGIN
      WCAMPO= TRIM(WCAMPO);
      sentencia =  'IF (new.'||:WCAMPO ||'IS NOT NULL) THEN '||
       'BEGIN '||
         'IF (OLD.'||:WCAMPO||' <> NEW.'||:WCAMPO||' ) THEN ' ||
           'INSERT INTO AUDITORIA (IDAUDITORIA, FECHA, USUARIO, IDREGISTRO,'||
                                   'TABLA, CAMPO, VALORVIEJO,VALORNUEVO) '||
            'VALUES (GEN_ID(AUDITORIA,1), '||'''NOW'''||', NEW.USUARIOMODIF, NEW.IDPOLIZA,'||
                                 '''POLIZA'','''||:WCAMPO||''', CAST(OLD.'||:WCAMPO||' AS VARCHAR(50)),CAST( NEW.'||:WCAMPO||' AS VARCHAR(50)) ); '||
       'END' ;
    END
    execute statement sentencia;

end
__________________
Cuando los grillos cantan, es que es de noche - viejo proverbio chino -
Responder Con Cita
  #3  
Antiguo 06-04-2010
Avatar de fjcg02
[fjcg02] fjcg02 is offline
Miembro Premium
 
Registrado: dic 2003
Ubicación: Zamudio
Posts: 1.412
Poder: 22
fjcg02 Va camino a la fama
Bueno,
parece que lo que quiero hacer es imposible. El ámbito de las variables old y new no sobrepasa más allá del propio trigger, por lo que es imposible que sean accedidas desde la sentencia 'execute statement'.
Por lo tanto tendré que orientar la solución hacia otro lado

Un new.saludo
__________________
Cuando los grillos cantan, es que es de noche - viejo proverbio chino -
Responder Con Cita
  #4  
Antiguo 06-04-2010
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.257
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
¿No sería más simple mantener una tabla donde se copiaran tal cual cada registro completo de las tablas que quieres auditar?

Por ejemplo, para la tabla "tbClientes" tendríamos "tbClientesAud", que sería igual que "tbClientes" pero sin restricción de campos nulos, valores por defecto, claves foráneas, etc.
Y en los trigger después de grabar, actualizar y borrar de tbClientes se graban los datos en tbClientesAud, puedes añadir algún campo como el de fechahora de la grabación y otro para guardar si fue un borrado, update o insert.

El Problema es que si son muchas tablas es un poco engorroso, no se parece en nada al "automatismo" que quieres hacer.

Aquí hay algo que puede interesarte, échale un vistazo.

A la espera de lo que nos traiga la versión 3 de Firebird, que promete bastante:

* Monitoring
* Asynchronous statement cancellation
* Embedded users / SQL users management
* More built-in functions
* Temporary tables
* SQL functions
* Recursive queries
* Faster outer joins
* SMP support in SS
* Compiled statements cache
* External functions/procedures

* Detailed logging/audit
* SQL tracing/profilingUser permissions for metadata
* Pluggable authentication modules
* Security groups
* Long exact numeric implementation
* Domains everywhere
* Regular expressions
* TEXT BLOB compatible with [VAR]CHAR
* Reliable logical backup
* Optimizer improvements
* Statement consistency/atomicy, read committed compliance
* Optimized network protocol
* Bi-directional indices
* Referential integrity without indices
* Bulk load/import

* PSQL debugging extensions/hooks
* Database encryption
* More access paths
* Full-text search
* Clustering
* Bi-directional cursors
* XML integration
Responder Con Cita
  #5  
Antiguo 06-04-2010
Avatar de fjcg02
[fjcg02] fjcg02 is offline
Miembro Premium
 
Registrado: dic 2003
Ubicación: Zamudio
Posts: 1.412
Poder: 22
fjcg02 Va camino a la fama
Gracias por tu opinión Casimiro, pero he descartado esa idea ( la de tablas 'clon' ) ya que son tropecientas tablas. Respecto a esperar nuevas funcionalidades de firebird, pues no creo que pueda esperar, es decir, seguiré para adelante.

Sí he visto un código ( que por cierto estoy buscando en la red ) que a lo más que llega es a generarte el trigger de manera automática en base a información que el usuario introduzca. Será ésta la solución que adopte, ya que me parece la más sencilla. Además, espero que los usuarios no cambien demasiado los campos que quieran auditar, dándoles ya unos triggers por defecto.

Un old.saludo
__________________
Cuando los grillos cantan, es que es de noche - viejo proverbio chino -
Responder Con Cita
  #6  
Antiguo 07-04-2010
erickperez6 erickperez6 is offline
Miembro
 
Registrado: may 2003
Posts: 152
Poder: 22
erickperez6 Va por buen camino
Cita:
* Monitoring
* Asynchronous statement cancellation
* Embedded users / SQL users management
* More built-in functions
* Temporary tables
* SQL functions
* Recursive queries
* Faster outer joins
* SMP support in SS
* Compiled statements cache
* External functions/procedures

* Detailed logging/audit
* SQL tracing/profilingUser permissions for metadata
* Pluggable authentication modules
* Security groups
* Long exact numeric implementation
* Domains everywhere
* Regular expressions
* TEXT BLOB compatible with [VAR]CHAR
* Reliable logical backup
* Optimizer improvements
* Statement consistency/atomicy, read committed compliance
* Optimized network protocol
* Bi-directional indices
* Referential integrity without indices
* Bulk load/import

* PSQL debugging extensions/hooks
* Database encryption
* More access paths
* Full-text search
* Clustering
* Bi-directional cursors
* XML integration
Saludos casimiro, de verdad esta muy interesante los nuevos features de firebire 3, me gustaria leer mas detalladamente algunos de los puntos listados mas arriba, pero he dado muchas vueltas en la pagina de firebiresql.org y aparte del track detail no encuentro nada detallado de las nuevas funcionabilidades
Responder Con Cita
  #7  
Antiguo 07-04-2010
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.257
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Sólo he visto la lista esa en su "roadmap", pero vienen comentarios, yo no los he encontrado
Responder Con Cita
  #8  
Antiguo 14-04-2010
Avatar de Cañones
Cañones Cañones is offline
Miembro
 
Registrado: ene 2007
Ubicación: La Paz Entre Ríos
Posts: 354
Poder: 18
Cañones Va por buen camino
Cita:
Empezado por fjcg02 Ver Mensaje
Gracias por tu opinión Casimiro, pero he descartado esa idea ( la de tablas 'clon' ) ya que son tropecientas tablas.
En mi oponión, uso tablas clon como las llamas, hechas a mano. Pero le agrego cuatro campos extras, timestamp de la modificación, acción realizada(Insert, Update, Delete), usuario (de la DB) y direccion ip.

Por otro lado, la variable para el nombre del campo tendría que ser Varchar(255) que creo que es el máximo de caracteres posible para nombres de tablas.

Espero te sirva de algo.
Saludos.
Responder Con Cita
  #9  
Antiguo 14-04-2010
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.257
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Muy interesante!, es una buena idea tal y como comentas que lo haces.
Responder Con Cita
  #10  
Antiguo 15-04-2010
Avatar de Cañones
Cañones Cañones is offline
Miembro
 
Registrado: ene 2007
Ubicación: La Paz Entre Ríos
Posts: 354
Poder: 18
Cañones Va por buen camino
Si les sirve les paso el trigger completo para controlar la auditoria.
Responder Con Cita
  #11  
Antiguo 15-04-2010
Avatar de fjcg02
[fjcg02] fjcg02 is offline
Miembro Premium
 
Registrado: dic 2003
Ubicación: Zamudio
Posts: 1.412
Poder: 22
fjcg02 Va camino a la fama
Cita:
Empezado por Cañones Ver Mensaje
Si les sirve les paso el trigger completo para controlar la auditoria.
Si no es molestia ,estaría muy agradecido de ver cómo lo resuelves.

Por cierto, tienes algún generador de los scripts para generar las tablas de auditoría ??

Hace unos días lo tenía claro, pero ahora no tanto, y finalmente no sé lo que haré, de ahí que esté interesado.

Un saludo
__________________
Cuando los grillos cantan, es que es de noche - viejo proverbio chino -
Responder Con Cita
  #12  
Antiguo 15-04-2010
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.257
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Cita:
Empezado por Cañones Ver Mensaje
Si les sirve les paso el trigger completo para controlar la auditoria.
Pues claro, hombre, eso ni se pregunta
Responder Con Cita
  #13  
Antiguo 15-04-2010
Avatar de Cañones
Cañones Cañones is offline
Miembro
 
Registrado: ene 2007
Ubicación: La Paz Entre Ríos
Posts: 354
Poder: 18
Cañones Va por buen camino
Cita:
Empezado por fjcg02 Ver Mensaje
Por cierto, tienes algún generador de los scripts para generar las tablas de auditoría ??
Un saludo
La verdad que no, porque ni bien creo la tabla la cual lleva una auditoría, le agrego los demás campos y creo la tabla de auditoría.
Responder Con Cita
  #14  
Antiguo 15-04-2010
Avatar de Cañones
Cañones Cañones is offline
Miembro
 
Registrado: ene 2007
Ubicación: La Paz Entre Ríos
Posts: 354
Poder: 18
Cañones Va por buen camino
Por ejemplo tengo esta tabla de Artículos
Código SQL [-]
CREATE TABLE ARTICULOS
(
  IDARTICULO Integer NOT NULL, // ID DE TABLA, USO UN GENERADOR
  CODIGO_INTERNO Varchar(20) NOT NULL,
  CODIGO_EXTERNO Varchar(20) NOT NULL,
  DESCRIPCION Varchar(80) NOT NULL,
  COMPATIBILIDAD Varchar(200) NOT NULL,
  IDLINEA Integer NOT NULL,
  IDRUBRO Integer NOT NULL,
  IDTITULO Integer NOT NULL,
  IDPROVEEDOR Integer NOT NULL,
  PRECIO_LISTA Numeric(18,4) NOT NULL,
  DESCUENTO Numeric(18,4) NOT NULL,
  IVA Numeric(18,4) NOT NULL,
  BENEFICIO_SOS Numeric(18,4) NOT NULL,
  BENEFICIO_MOVIL Numeric(18,4) NOT NULL,
  CONTROL_STOCK BINARIO DEFAULT 0 NOT NULL,
  STOCK Integer NOT NULL,
  PUNTO_REPOSICION Integer NOT NULL,
  FECHA_COMPRA Date NOT NULL,
  FECHA_ACTPRECIO Date NOT NULL,
  FECHA_BAJA Date,
  PRIMARY KEY (IDARTICULO)
);

Hago la tabla de auditoria
Código SQL [-]
CREATE TABLE ARTICULOS_AUDITORIA
(
  IDTRANSACCION Integer NOT NULL,
  IDARTICULO Integer NOT NULL,
  CODIGO_INTERNO Varchar(20) NOT NULL,
  CODIGO_EXTERNO Varchar(20) NOT NULL,
  DESCRIPCION Varchar(80) NOT NULL,
  COMPATIBILIDAD Varchar(200) NOT NULL,
  IDLINEA Integer NOT NULL,
  IDRUBRO Integer NOT NULL,
  IDTITULO Integer NOT NULL,
  IDPROVEEDOR Integer NOT NULL,
  PRECIO_LISTA Numeric(18,4) NOT NULL,
  DESCUENTO Numeric(18,4) NOT NULL,
  IVA Numeric(18,4) NOT NULL,
  BENEFICIO_SOS Numeric(18,4) NOT NULL,
  BENEFICIO_MOVIL Numeric(18,4) NOT NULL,
  CONTROL_STOCK BINARIO DEFAULT 0 NOT NULL,
  STOCK Integer NOT NULL,
  PUNTO_REPOSICION Integer NOT NULL,
  FECHA_COMPRA Date NOT NULL,
  FECHA_ACTPRECIO Date NOT NULL,
  FECHA_BAJA Date,
  FECHA_HORA Timestamp DEFAULT 'NOW' NOT NULL, // FECHA Y HORA DEL REGISTRO
  USUARIO Char(31) NOT NULL, // USR DE LA BD
  ACCION Varchar(20) NOT NULL, // ACCION QUE REALIZA
  REMOTE_ADDRESS Varchar(253) NOT NULL, // DIRECCION DESDE DONDE ACCEDE
  PRIMARY KEY (IDTRANSACCION)
);

El trigger, es un poco largo, pero funciona. Se puede mejorar pero no he tenido tiempo de hacerlo
Código SQL [-]
SET TERM ^ ;
CREATE TRIGGER TG_AUDITORIA_ARTICULOS FOR ARTICULOS ACTIVE
BEFORE INSERT OR UPDATE OR DELETE POSITION 0
AS 
DECLARE VARIABLE vACCION VARCHAR(6);
/* INSERT insercion - UPDATE actualizacion - DELETE eliminacion - DOWN baja logica - UP alta logica */
BEGIN 
  /* VEO QUE ACCION SE LLEVA A CABO */
  IF (INSERTING) THEN
    /* HAGO UN INSERT EN ARTICULOS_AUDITORIA CON LOS DATOS DEL ARTICULO */
    BEGIN
    vACCION='INSERT';
    INSERT INTO ARTICULOS_AUDITORIA (IDTRANSACCION, IDARTICULO, CODIGO_INTERNO, CODIGO_EXTERNO, DESCRIPCION, COMPATIBILIDAD, IDLINEA, IDRUBRO, IDTITULO, IDPROVEEDOR, PRECIO_LISTA, DESCUENTO, IVA, BENEFICIO_SOS, BENEFICIO_MOVIL, CONTROL_STOCK, STOCK, PUNTO_REPOSICION, FECHA_COMPRA, FECHA_ACTPRECIO, FECHA_BAJA, FECHA_HORA, USUARIO, ACCION, REMOTE_ADDRESS)
      VALUES (
      GEN_ID(GEN_IDTRANSACCION_ART, 1),
      NEW.IDARTICULO, 
      NEW.CODIGO_INTERNO, 
      NEW.CODIGO_EXTERNO, 
      NEW.DESCRIPCION, 
      NEW.COMPATIBILIDAD, 
      NEW.IDLINEA, 
      NEW.IDRUBRO, 
      NEW.IDTITULO, 
      NEW.IDPROVEEDOR, 
      NEW.PRECIO_LISTA, 
      NEW.DESCUENTO, 
      NEW.IVA, 
      NEW.BENEFICIO_SOS, 
      NEW.BENEFICIO_MOVIL, 
      NEW.CONTROL_STOCK, 
      NEW.STOCK, 
      NEW.PUNTO_REPOSICION, 
      NEW.FECHA_COMPRA, 
      NEW.FECHA_ACTPRECIO, 
      NEW.FECHA_BAJA, 
      'NOW', 
      (SELECT MON$USER
       FROM MON$ATTACHMENTS
       WHERE MON$ATTACHMENT_ID = CURRENT_CONNECTION),
      :vACCION, 
      (SELECT MON$REMOTE_ADDRESS
       FROM MON$ATTACHMENTS
       WHERE MON$ATTACHMENT_ID = CURRENT_CONNECTION)
      );
    END
  IF (UPDATING) THEN
    /* HAGO UN INSERT EN ARTICULOS_AUDITORIA CON LOS DATOS DEL ARTICULO */
    BEGIN
    IF (NEW.FECHA_BAJA IS NOT NULL) THEN
      vACCION='DOWN'; /* SE PRODUCE UNA BAJA LOGICA */
    ELSE
      IF ((OLD.FECHA_BAJA IS NOT NULL) AND (NEW.FECHA_BAJA IS NULL)) THEN
        vACCION='UP';
      ELSE
        vACCION='UPDATE'; /* UNA ACTUALIZACION */
    INSERT INTO ARTICULOS_AUDITORIA (IDTRANSACCION, IDARTICULO, CODIGO_INTERNO, CODIGO_EXTERNO, DESCRIPCION, COMPATIBILIDAD, IDLINEA, IDRUBRO, IDTITULO, IDPROVEEDOR, PRECIO_LISTA, DESCUENTO, IVA, BENEFICIO_SOS, BENEFICIO_MOVIL, CONTROL_STOCK, STOCK, PUNTO_REPOSICION, FECHA_COMPRA, FECHA_ACTPRECIO, FECHA_BAJA, FECHA_HORA, USUARIO, ACCION, REMOTE_ADDRESS)
      VALUES (
      GEN_ID(GEN_IDTRANSACCION_ART, 1),
      NEW.IDARTICULO, 
      NEW.CODIGO_INTERNO, 
      NEW.CODIGO_EXTERNO, 
      NEW.DESCRIPCION, 
      NEW.COMPATIBILIDAD, 
      NEW.IDLINEA, 
      NEW.IDRUBRO, 
      NEW.IDTITULO, 
      NEW.IDPROVEEDOR, 
      NEW.PRECIO_LISTA, 
      NEW.DESCUENTO, 
      NEW.IVA, 
      NEW.BENEFICIO_SOS, 
      NEW.BENEFICIO_MOVIL, 
      NEW.CONTROL_STOCK, 
      NEW.STOCK, 
      NEW.PUNTO_REPOSICION, 
      NEW.FECHA_COMPRA, 
      NEW.FECHA_ACTPRECIO, 
      NEW.FECHA_BAJA, 
      'NOW', 
      (SELECT MON$USER
       FROM MON$ATTACHMENTS
       WHERE MON$ATTACHMENT_ID = CURRENT_CONNECTION),
      :vACCION, 
      (SELECT MON$REMOTE_ADDRESS
       FROM MON$ATTACHMENTS
       WHERE MON$ATTACHMENT_ID = CURRENT_CONNECTION)
      );
    END
  IF (DELETING) THEN
    /* HAGO UN INSERT EN ARTICULOS_AUDITORIA CON LOS DATOS DEL ARTICULO */
    BEGIN
    vACCION='DELETE';
    INSERT INTO ARTICULOS_AUDITORIA (IDTRANSACCION, IDARTICULO, CODIGO_INTERNO, CODIGO_EXTERNO, DESCRIPCION, COMPATIBILIDAD, IDLINEA, IDRUBRO, IDTITULO, IDPROVEEDOR, PRECIO_LISTA, DESCUENTO, IVA, BENEFICIO_SOS, BENEFICIO_MOVIL, CONTROL_STOCK, STOCK, PUNTO_REPOSICION, FECHA_COMPRA, FECHA_ACTPRECIO, FECHA_BAJA, FECHA_HORA, USUARIO, ACCION, REMOTE_ADDRESS)
      VALUES (
      GEN_ID(GEN_IDTRANSACCION_ART, 1),
      OLD.IDARTICULO, 
      OLD.CODIGO_INTERNO, 
      OLD.CODIGO_EXTERNO, 
      OLD.DESCRIPCION, 
      OLD.COMPATIBILIDAD, 
      OLD.IDLINEA, 
      OLD.IDRUBRO, 
      OLD.IDTITULO, 
      OLD.IDPROVEEDOR, 
      OLD.PRECIO_LISTA, 
      OLD.DESCUENTO, 
      OLD.IVA, 
      OLD.BENEFICIO_SOS, 
      OLD.BENEFICIO_MOVIL, 
      OLD.CONTROL_STOCK, 
      OLD.STOCK, 
      OLD.PUNTO_REPOSICION, 
      OLD.FECHA_COMPRA, 
      OLD.FECHA_ACTPRECIO, 
      OLD.FECHA_BAJA, 
      'NOW', 
      (SELECT MON$USER
       FROM MON$ATTACHMENTS
       WHERE MON$ATTACHMENT_ID = CURRENT_CONNECTION),
      :vACCION, 
      (SELECT MON$REMOTE_ADDRESS
       FROM MON$ATTACHMENTS
       WHERE MON$ATTACHMENT_ID = CURRENT_CONNECTION)
      );
    END
END^
SET TERM ; ^
UPDATE RDB$TRIGGERS set
  RDB$DESCRIPTION = 'TG PARA AUDITAR LAS MODIFICACIONES EN LA TABLA DE ARTICULOS'
  where RDB$TRIGGER_NAME = 'TG_AUDITORIA_ARTICULOS';

Eso es todo.
Espero les sirva.
Saludos de Cañones

PD: cualquier duda, preguntan nomas. No contesto de inmediato porque no me llegan las notificaciones.

Última edición por Cañones fecha: 15-04-2010 a las 21:33:56. Razón: PD
Responder Con Cita
  #15  
Antiguo 15-04-2010
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.257
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Gracias !!!
Responder Con Cita
  #16  
Antiguo 16-04-2010
Avatar de fjcg02
[fjcg02] fjcg02 is offline
Miembro Premium
 
Registrado: dic 2003
Ubicación: Zamudio
Posts: 1.412
Poder: 22
fjcg02 Va camino a la fama
Gracias por la información.
Intentaré preparar un Store Procedure o una función que me genere los triggers.

No lo voy a hacer de forma inmediata, pero intentaré publicar el resultado.

Un saludo
__________________
Cuando los grillos cantan, es que es de noche - viejo proverbio chino -
Responder Con Cita
  #17  
Antiguo 07-04-2011
Avatar de fjcg02
[fjcg02] fjcg02 is offline
Miembro Premium
 
Registrado: dic 2003
Ubicación: Zamudio
Posts: 1.412
Poder: 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
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Sistema de Huellas (Pistas de auditoria) Hagen Firebird e Interbase 3 29-03-2011 14:47:12
Trigger dinámico para Auditoría de Tablas jwmoreira Firebird e Interbase 6 11-03-2010 23:53:07
Realizar auditoria de acciones de usuarios mantrax Seguridad 3 19-10-2007 06:42:33
Un trigger que dispara un procedimiento que dispara un trigger... sitrico Firebird e Interbase 5 04-06-2007 23:05:13
Triggers de auditoria en firebird 1.5 robertoe Firebird e Interbase 1 04-01-2007 05:18:11


La franja horaria es GMT +2. Ahora son las 02:12:41.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi