У меня есть таблица пользователя с идентификаторами и именами пользователей (и другими сведениями) и несколькими другими таблицами, ссылающимися на эту таблицу с различными именами столбцов (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..