Написал очередную уродливую, но работающую, реализацию алгоритма получения имени текущего метода. Это нужно, например, при выводе сообщений об ошибках системы, типа
"Ошибка в строке #17 метода PKG_PERSONS.CreateNewPerson(..): Не указана фамилия физического лица"
Очередная она потому что какой
Короче, выглядит все это вот так:
function get_fname(p_unit in varchar2, p_line in number) return varchar2
is
l_name varchar2(30);
begin
select distinct
max(tt.proc_name) keep (dense_rank last order by tt.line) over() text
into l_name
from
(
select
t.proc_name,
t.line
from
(
select
regexp_substr(text, '(^|;\s*|\s+is\s+|)(procedure| function)\s+(return)*(\w+)\s*( \(|is)*',1,1,'i',4) proc_name,
line
from
user_source s
where
s.type in ('TYPE BODY', 'PACKAGE BODY', 'TRIGGER', 'PROCEDURE', 'FUNCTION') and
s.name = upper(p_unit) and
line <= p_line
) t
where t.proc_name is not null and
upper(t.proc_name) in (select procedure_name from user_procedures p where p.object_name = upper(p_unit))
order by line
) tt;
return '"' || UPPER(sys_context('USERENV', 'CURRENT_SCHEMA')) || '"' || '.' || '"' || l_name || '"';
end;
Пакет, в котором размещена функция, создан с указанием AUTHID CURRENT_USER.
Вызов метода в коде:
...
raise_application_error(-20001, 'Ошибка в строке #'||$$PLSQL_LINE||' метода ' || PKG_DEBUG_TOOLS.get_fname($$PLSQL_UNIT, $$PLSQL_LINE) || '(..): Не указана фамилия физического лица');'
...
P.S. Функцию поиска имени метода в USER_SOURCE, конечно, можно обмануть, вставив, например, между объявлением метода пакета и вызовом функции литерал, в котором будет описан вызов какого-либо другого метода пакета, только вот зачем...
P.P.S. 02.10.2013 Переписал метод, чтобы было более красиво и менее ресурсоемко, заодно исправил ошибку в разборе имени функции
P.S. Функцию поиска имени метода в USER_SOURCE, конечно, можно обмануть, вставив, например, между объявлением метода пакета и вызовом функции литерал, в котором будет описан вызов какого-либо другого метода пакета, только вот зачем...
P.P.S. 02.10.2013 Переписал метод, чтобы было более красиво и менее ресурсоемко, заодно исправил ошибку в разборе имени функции
P.P,P.S. 10.03.2023 Понаписал за прошедшее время разных определялок текущих методов и пакетов. Вот прилагаю, если у кого-то еще остались вопросы. Выбираем на свой вкус. Я сейчас предпочитаю п2 для определения текущего метода и п3 для определения текущего пакета (oracle 19c).
- ThisPackageAndMethod varchar2(128) := regexp_substr(regexp_substr(dbms_utility.format_call_stack, 'package\s+body\s+([^[:space:]]+)',1,1,'i',1), '[^.]+[.][^.]+$');
- ThisMethod varchar2(128) := utl_call_stack.concatenate_subprogram(utl_call_stack.subprogram(1));
- ThisPackage varchar2(128) := $$PLSQL_UNIT;
- ThisPackage varchar2(128) := nvl(regexp_substr(dbms_utility.format_call_stack, 'package\sbody\s(((\w)+[.])?(\w+))',1,1,'i',4), 'task_'||to_char(sysdate, 'YYYYMMDDHH24MISS'));