martes, 15 de junio de 2010

Activar o desactivar un trigger en SQL

Esta mañana un amigo se ha encontrado con el problema de saber si un trigger se encuentra activado o no en SQL Server 2000 así que nos hemos puesto a googlear pero solo hemos encontrado información para activar o desactivar un trigger.

En SQL Server 2000 existen dos comandos T-SQL que permiten activar o desactiavar un trigger.

Activar un trigger
ALTER TABLE [nombre_tabla] ENABLE TRIGGER [nombre_triger]

Desactivar un trigger
ALTER TABLE [nombre_tabla] DISABLE TRIGGER [nombre_triger]

Pero ¿hay alguna forma de saber el estado actual de un trigger?, es decir, ¿podemos saber si el trigger se encuentra activado o desactivado?. SQL si debe almacenar esta información en algún sitio pero ¿donde?. La primera idea que se me pasó por la cabeza fué mirar en la tabla de sistema sysobjects, a fin de cuentas, un trigger es un objeto más de la base de datos, pero, aparentemente, ninguno de los campos de sysobjects hace referencia directa al estado del trigger y, en la ayuda sobre dicha tabla tampoco se menciona esta opción pero aún así vamos a hacer la prueba comprobando los valores de sysobjects antes y después de desactivar un trigger de forma que podamos ver si se produce algún cambio en la información.

Primero activamos el trigger (aunque se supone que debe estar activado ya que es el comportamiento por defecto cuando se crea un trigger) y luego hacemos la SELECT sobre sysobjects para ver que contiene.



Después desactivamos el trigger y volvemos a ejecutar la SELECT sobre sysobjects.



Podemos ver que solo ha cambiado el valor de la columna status así que parece ser que es en dicho campo donde SQL guarda la información sobre el estado del trigger (activado/desactivado) y, por el nombre, status, parece lógico pese a que en la documentación de sysobjects no se mencione nada al respecto.

Cuando el trigger estaba activado el valor de la columna status era 1610614528 y cuando lo desactivamos la columna status pasa a tener el valor 1610616576 ¿que significan estos valores? No hay mucha documentación sobre el campo status pero tiene toda la pinta de ser que es un campo "flag" donde se guarda información a nivel de bit sobre el estado de determinadas funciones así que vamos a pasar a binario los valores obtenidos.

1610614528 -> 1100000000000000000011100000000 (binario)
1610616576 -> 1100000000000000000111100000000 (binario)

Esto tiene buena pinta. En binario los dos valores son exactamente iguales a excepción de uno de los bits así que se puede suponer que ese bit es el que indica si el trigger esta desactivado o no. Cuando ese valor se encuentre a 1 indicará que el trigger está desactivado y cuando se encuentre a 0 indicará que el trigger está activado.

Si ponemos a cero todos los valores exepto el que nos interesa obtendremos la mascara que debemos validar para saber el estado de un trigger.

1610614528 -> 1100000000000000000011100000000 (binario)
1610616576 -> 1100000000000000000111100000000 (binario)
 (mascara) -> 0000000000000000000100000000000 (binario)
 (mascara) -> 0x800 (hexadecimal)

Por comodidad he pasado su valor a hexadecimal para montar una SELECT que nos indique el estado de nuestro trigger de ejemplo.

SELECT name, CASE WHEN status & 0x800 = 0 THEN 1 ELSE 0 END as TriggerActivado

FROM sysobjects WHERE name = 'miTrigger'


Hay que tener en cuenta que Microsoft dice expresamente que la columna status de la tabla sysobjects esta reservada a uso interno por lo que se supone que podrian modificar su funcionalidad sin previo aviso aunque, hasta la fecha, sigue manteniendo este comportamiento pese a que ya existen versiones superiores a SQL Server 2000.

3 comentarios:

  1. Algo parecido ocurre con las claves ajenas aunque imagino que se puede extender a constraints

    ALTER TABLE [TABLA] NOCHECK CONSTRAINT [FK]
    ALTER TABLE [TABLA] CHECK CONSTRAINT [FK]

    Con esta select podemos obtener el estado de la foreign key directamente de sysobjects

    SELECT
    CASE WHEN FKS.STATUS & 0x100 = 0 THEN 1 ELSE 0 END FK_ENABLED, NAME
    FROM SYSOBJECTS FKS
    WHERE XTYPE = 'F'

    ResponderEliminar
  2. Gracias indigenica. En el campo status se guarda gran cantidad de información que lamentablemente no esta documentada pero no siempre es dificil obtenerla.

    ResponderEliminar
  3. Para saber que campos son autonuméricos hay que utilizar la máscara 0x80 en la columna STATUS de la tabla syscolumns


    SELECT name, CASE WHEN status & 0x80 = 0 THEN 0 ELSE 1 END as Autonumerico
    FROM syscolumns WHERE object_name(id) = 'miTabla'

    ResponderEliminar