У меня есть таблица пользователя с идентификаторами и именами пользователей (и другими сведениями) и несколькими другими таблицами, ссылающимися на эту таблицу с различными именами столбцов (CONSTRAINT some_name FOREIGN KEY (columnname) REFERENCES "user" (userid)). Мне нужно добавить имена пользователей в ссылочные таблицы (при подготовке к отбрасыванию всей таблицы пользователя). Это, конечно, легко выполняется с помощью одиночных ALTER TABLE и UPDATE, и хранение этих современных триггеров также (довольно) легко. Но это триггерная функция, которая вызывает у меня некоторое раздражение. Я мог бы использовать отдельные функции для каждой таблицы, но это казалось излишним, поэтому для этой цели я создал одну общую функцию:
CREATE OR REPLACE FUNCTION public.add_username() RETURNS trigger AS
$BODY$
  DECLARE
    sourcefield text;
    targetfield text;
    username text;
    existing text;
  BEGIN
    IF (TG_NARGS != 2) THEN
      RAISE EXCEPTION 'Need source field and target field parameters';
    END IF;
    sourcefield = TG_ARGV[0];
    targetfield = TG_ARGV[1];
    EXECUTE 'SELECT username FROM "user" WHERE userid = ($1).' || sourcefield INTO username USING NEW;
    EXECUTE format('SELECT ($1).%I', targetfield) INTO existing USING NEW;
    IF ((TG_OP = 'INSERT' AND existing IS NULL) OR (TG_OP = 'UPDATE' AND (existing IS NULL OR username != existing))) THEN
      CASE targetfield
        WHEN 'username' THEN
          NEW.username := username;
        WHEN 'modifiername' THEN
          NEW.modifiername := username;
        WHEN 'creatorname' THEN
          NEW.creatorname := username;
        .....
      END CASE;
    END IF;
    RETURN NEW;
  END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;
И используя функцию триггера:
CREATE TRIGGER some_trigger_name BEFORE UPDATE OR INSERT ON my_schema.my_table FOR EACH ROW EXECUTE PROCEDURE public.add_username('userid', 'username');
Как это работает, функция триггера получает имя исходного источника (например userid) и имя целевого поля (username) через TG_ARGV. Затем они используются для заполнения (возможно) отсутствующей информации. Все это работает достаточно хорошо, но как я могу избавиться от этого CASE -mess? Есть ли способ динамически изменять значения в записи NEW, когда я не знаю названия поля заранее (точнее, может быть много чего)? Он находится в параметре targetfield, но, очевидно, NEW.targetfield не работает, или что-то вроде NEW[targetfield] (например, Javascript).
Любые идеи о том, как это можно сделать? Помимо использования, например, PL/Python..
