Работает:
DECLARE
l_table_name varchar(30) := lower(p_table_name);
BEGIN
EXECUTE 'ALTER TYPE obj_name_tp ADD VALUE IF NOT EXISTS '||quote_literal(l_table_name);
Во-первых, не было никакого смысла передавать значение переменной в качестве плейсхолдера, т.к. EXECUTE находится в области видимости блока BEGIN, в котором эта переменная задекларирована.
Во-вторых, я пытался использовать функцию quote_ident(), которая оборачивает текст в
двойные кавычки. Однако двойные кавычки (наряду с символами $$) используются для "прерывания" самого plpgsql-кода. Получалось, что я пытался вызвать ALTER TYPE без параметра, т.к. значение после EXISTS отсекалось.