Это немного упрощенно, но при условии, что запущены 9.2
или более поздние версии, это пример того, как проверить единственную разрешенную функцию, выполняющую вставку:
CREATE TABLE my_table (col1 text, col2 integer, col3 timestamp);
CREATE FUNCTION my_table_insert_function(col1 text, col2 integer) RETURNS integer AS $$
BEGIN
INSERT INTO my_table VALUES (col1, col2, current_timestamp);
RETURN 1;
END $$ LANGUAGE plpgsql;
CREATE FUNCTION my_table_insert_trigger_function() RETURNS trigger AS $$
DECLARE
stack text;
fn integer;
BEGIN
RAISE EXCEPTION 'secured';
EXCEPTION WHEN OTHERS THEN
BEGIN
GET STACKED DIAGNOSTICS stack = PG_EXCEPTION_CONTEXT;
fn := position('my_table_insert_function' in stack);
IF (fn <= 0) THEN
RAISE EXCEPTION 'Expecting insert from my_table_insert_function'
USING HINT = 'Use function to insert data';
END IF;
RETURN new;
END;
END $$ LANGUAGE plpgsql;
CREATE TRIGGER my_table_insert_trigger BEFORE INSERT ON my_table
FOR EACH ROW EXECUTE PROCEDURE my_table_insert_trigger_function();
И быстрый пример использования:
INSERT INTO my_table VALUES ('test one', 1, current_timestamp); -- FAILS
SELECT my_table_insert_function('test one', 1); -- SUCCEEDS
Вы захотите заглянуть в стек более подробно, если хотите, чтобы ваш код был более надежным, безопасным и т. Д. Конечно, возможны проверки для нескольких функций, но они требуют больше работы. Разделение стека на несколько строк и его синтаксический анализ могут быть довольно сложными, поэтому, возможно, вам понадобятся некоторые вспомогательные функции, если все станет сложнее.
Это просто доказательство концепции, но она делает то, что заявляет. Я ожидаю, что этот код будет довольно медленным, учитывая использование обработки исключений и проверки стека, поэтому не используйте его в критически важных для вашего приложения частях приложения. Это вряд ли подходит для случаев, когда операторы DML
встречаются часто, но если безопасность важнее, чем производительность, сделайте это.