Saltar al contenido

¿Cómo usar dinámicamente TG_TABLE_NAME en PostgreSQL 8.2?

Este tutorial fue probado por nuestros especialistas así aseguramos la veracidad de nuestro contenido.

Solución:

Estaba buscando exactamente lo mismo hace un par de años. ¡Una función de activación para gobernarlos a todos! Pregunté en las listas de Usenet, probé varios enfoques, sin éxito. El consenso al respecto fue esto no se pudo hacer. Una deficiencia de PostgreSQL 8.3 o anterior.

Desde PostgreSQL 8.4 tu puedes sólo:

EXECUTE 'INSERT INTO ' || TG_RELID::regclass::text || ' SELECT ($1).*'
USING NEW;

Con la pg 8.2 tienes un problema:

  • no puede acceder dinámicamente a las columnas de NEW / OLD. Debe conocer los nombres de las columnas al momento de escribir la función de activación.
  • NEW / OLD no se ven por dentro EXECUTE.
  • EXECUTE .. USING no ha nacido todavía.

Sin embargo, hay un truco.

Cada nombre de tabla en el sistema puede servir como tipo compuesto del mismo nombre. Por lo tanto, puede crear una función que tome NEW / OLD como parámetro y ejecutar eso. Puede crear y destruir dinámicamente esa función en cada evento desencadenante:

Función de disparo:

CREATE OR REPLACE FUNCTION trg_cdc()
  RETURNS trigger AS
$func$
DECLARE
   op      text := TG_OP || '_' || TG_WHEN;
   tbl     text := quote_ident(TG_TABLE_SCHEMA) || '.'
                || quote_ident(TG_TABLE_NAME);
   cdc_tbl text := quote_ident(TG_TABLE_SCHEMA) || '.'
                || quote_ident('cdc_' || TG_TABLE_NAME);
BEGIN

EXECUTE 'CREATE FUNCTION f_cdc(n ' || tbl || ', op text)
  RETURNS void AS $x$ BEGIN
  INSERT INTO ' || cdc_tbl || ' SELECT op, (n).*;
END $x$ LANGUAGE plpgsql';

CASE TG_OP
WHEN 'INSERT', 'UPDATE' THEN
   PERFORM f_cdc(NEW, op);
WHEN 'DELETE' THEN
   PERFORM f_cdc(OLD, op);
ELSE
   RAISE EXCEPTION 'Unknown TG_OP: "%". Should not occur!', TG_OP;
END CASE;

EXECUTE 'DROP FUNCTION f_cdc(' || tbl || ', text)';

IF TG_OP = 'DELETE' THEN
    RETURN OLD;
ELSE
    RETURN NEW;
END IF;

END
$func$  LANGUAGE plpgsql;

Generar:

CREATE TRIGGER cdc
BEFORE INSERT OR UPDATE OR DELETE ON my_tbl
FOR EACH ROW EXECUTE PROCEDURE trg_cdc();

Los nombres de las tablas deben tratarse como una entrada del usuario. Usar quote_ident() para defenderse de la inyección de SQL.

Sin embargo, de esta manera crea y suelta una función para cada evento desencadenante. Bastante sobrecarga, yo no iría por eso. Tendrá que aspirar mucho algunas tablas de catálogo.

término medio

PostgreSQL admite la sobrecarga de funciones. Por lo tanto, una función por tabla del mismo nombre básico (pero diferente tipo de parámetro) pueden coexistir. Podría tomar el término medio y reducir drásticamente el ruido creando f_cdc(..) una vez por tabla al mismo tiempo que crea el disparador. Esa es una pequeña función por tabla. Debe observar los cambios en las definiciones de las tablas, pero las tablas no deberían cambiar con tanta frecuencia. Remover CREATE y DROP FUNCTION desde la función de gatillo, llegando a un gatillo pequeño, rápido y elegante.

Podría verme haciendo eso en la página 8.2. Excepto que no puedo verme haciendo cualquier cosa en la página 8.2 más. Llegó al final de su vida útil en diciembre de 2011. Después de todo, tal vez puedas actualizarlo de alguna manera.

Calificaciones y reseñas

Agradecemos que quieras reafirmar nuestra labor exponiendo un comentario y dejando una valoración te damos las gracias.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *