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 *************/