Skip to content

Instantly share code, notes, and snippets.

@jgebal
Created June 15, 2018 01:15
Show Gist options
  • Save jgebal/7c7b3f8e77056e8aa8d64d70cc7e9cab to your computer and use it in GitHub Desktop.
Save jgebal/7c7b3f8e77056e8aa8d64d70cc7e9cab to your computer and use it in GitHub Desktop.
Little utility to get call procedure/function parameter names in PLSQL
create or replace package checker is
subtype t_exception_no is pls_integer range -20500..-20000;
c_null_value constant t_exception_no := -20001;
procedure raise_if_null(p_value varchar2);
end;
/
create or replace package body checker is
type r_caller_info is record(
owner varchar2(250),
name varchar2(250),
line_no positive
);
function who_called(
p_level positiven := 1
) return r_caller_info is
c_pattern constant varchar2(500) := '^((.*'||CHR(10)||'){'||(p_level+4)||'})(.*)'||CHR(10);
c_stack constant varchar2(32767) := dbms_utility.format_call_stack();
c_stack_offset constant integer := 4;
l_stack_line varchar2(4000);
l_result r_caller_info;
begin
l_stack_line := regexp_substr( c_stack, c_pattern, 1, 1, '', 3);
if l_stack_line like '%.%' then
l_result.line_no := to_number( regexp_substr(l_stack_line, '(0x)?[0-9a-f]+\s+(\d+)', subexpression => 2) );
l_result.owner := regexp_substr( l_stack_line, '([A-Za-z0-9$#_]+)\.([A-Za-z0-9$#_]|\.)+', subexpression => 1);
l_result.name := regexp_substr( l_stack_line, '([A-Za-z0-9$#_]+)\.([A-Za-z0-9$#_]+)', subexpression => 2);
end if;
-- dbms_output.put_line(c_stack);
-- dbms_output.put_line('l_result =('||l_result.owner||', '||l_result.name||', '||l_result.line_no||')' );
return l_result;
end;
function get_source_line(p_caller r_caller_info) return varchar2 is
l_line_text varchar2(4000);
begin
select /*+ first_rows(4) */
listagg(s.text) within group(order by s.line)
into l_line_text
from all_source s
where s.name = p_caller.name
and s.owner = p_caller.owner
and s.line between p_caller.line_no and p_caller.line_no + 4
and s.type = 'PACKAGE BODY';
-- dbms_output.put_line(l_line_text);
return l_line_text;
end;
function get_call_params(
p_line varchar2,
p_self_name varchar2
) return varchar2 is
begin
return
translate(
regexp_substr(
p_line
, '\s*'||$$PLSQL_UNIT||'\.'||p_self_name||'\s*\(([^\)]*)\)'
, 1, 1, 'i', 1
)
/*remove spaces, tabs and newlines*/
,'a '||chr(9)||chr(10)||chr(13)
,'a'
);
end;
procedure raise_if_null(p_value varchar2) is
l_param_name varchar2(4000);
begin
if p_value is null then
l_param_name := get_call_params(get_source_line(who_called()),'RAISE_IF_NULL');
raise_application_error(c_null_value,'Call parameter: "'||l_param_name||'" is null');
end if;
end;
end;
/
--Example:
create or replace type t_obj as object(
id integer,
name varchar2(100)
);
/
create or replace package some_api is
procedure do_stuff(p_obj t_obj);
end;
/
create or replace package body some_api is
procedure do_stuff(p_obj t_obj)
is
begin
checker.raise_if_null(
p_obj.id
);
commit;
exception
when others then
rollback;
raise;
end;
end;
/
--Check it
begin
some_api.do_stuff(t_obj(null,null));
end;
/
--Outcomes
/*************
ORA-20001: Call parameter: "p_obj.id" is null
ORA-06512: at "UT3_TESTER.SOME_API", line 12
ORA-06512: at "UT3_TESTER.CHECKER", line 67
ORA-06512: at "UT3_TESTER.SOME_API", line 5
ORA-06512: at line 2
*************/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment