sql >> Base de Datos >  >> RDS >> PostgreSQL

Disparador genérico para restringir las inserciones según el conteo

He estado haciendo un tipo similar de activadores genéricos. La parte más complicada es obtener la entrada de valor en NEW registro basado en el nombre de la columna.

Lo estoy haciendo de la siguiente manera:

  • convertir NEW datos en una matriz;
  • busca el attnum de la columna y utilícelo como un índice para la matriz.

Este enfoque funciona siempre que no haya comas en los datos :( No conozco otras formas de convertir NEW o OLD variables en la matriz de valores.

La siguiente función podría ayudar:

CREATE OR REPLACE FUNCTION impose_maximum() RETURNS trigger AS $impose_maximum$
DECLARE
  _sql  text;
  _cnt  int8;
  _vals text[];
  _anum int4;
  _im   record;

BEGIN
 _vals := string_to_array(translate(trim(NEW::text), '()', ''), ',');

 FOR _im IN SELECT * FROM imposed_maximums WHERE table_name = TG_TABLE_NAME LOOP
  SELECT attnum INTO _anum FROM pg_catalog.pg_attribute a
    JOIN pg_catalog.pg_class t ON t.oid = a.attrelid
   WHERE t.relkind = 'r' AND t.relname = TG_TABLE_NAME
     AND NOT a.attisdropped AND a.attname = _im.column_group;

  _sql := 'SELECT count('||quote_ident(_im.column_count)||')'||
          ' FROM '||quote_ident(_im.table_name)||
          ' WHERE '||quote_ident(_im.column_group)||' = $1';

  EXECUTE _sql INTO _cnt USING _vals[_anum];

  IF _cnt > CAST(_im.max_size AS int8) THEN
    RAISE EXCEPTION 'Maximum of % hit for column % in table %(%=%)',
      _im.max_size, _im.column_count,
      _im.table_name, _im.column_group, _vals[_anum];
  END IF;
 END LOOP;

 RETURN NEW;
END; $impose_maximum$ LANGUAGE plpgsql;

Esta función verificará todas las condiciones definidas para una tabla dada.