-
Notifications
You must be signed in to change notification settings - Fork 18
/
stk.sql
158 lines (116 loc) · 4.76 KB
/
stk.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
-- ---------------------------------------------------------------------------------------------------
--
-- Script: stk.sql
--
-- Author: Adrian Billington
-- www.oracle-developer.net
--
-- Description: A package for parsing the PL/SQL call stack. Includes functions to identify a
-- program's name or its caller.
--
-- Usage: Use in PL/SQL. The available functions are as follows:
--
-- a) WHOAMI returns either SCHEMA.OBJECT or anonymous block;
--
-- b) CALLER returns either SCHEMA.OBJECT or anonymous block of a program's
-- invoker. Additionally, the program name of any level in the stack can
-- be optionally returned;
--
-- c) PARSE is exposed to return an entire line of the stack at the supplied
-- depth.
--
-- ---------------------------------------------------------------------------------------------------
CREATE PACKAGE stk AS
FUNCTION parse (
depth_in IN PLS_INTEGER DEFAULT 2
) RETURN VARCHAR2;
FUNCTION caller (
depth_in IN PLS_INTEGER DEFAULT 3
) RETURN VARCHAR2;
FUNCTION whoami RETURN VARCHAR2;
END stk;
/
CREATE PACKAGE BODY stk AS
TYPE ntt_varchar2 IS TABLE OF VARCHAR2(1028);
FUNCTION string_to_table (
string_in IN VARCHAR2,
delimiter_in IN VARCHAR2 DEFAULT ','
) RETURN ntt_varchar2 IS
v_wkg_str VARCHAR2(32767) := string_in || delimiter_in;
v_pos PLS_INTEGER;
nt_return ntt_varchar2 := ntt_varchar2();
BEGIN
LOOP
v_pos := INSTR(v_wkg_str,delimiter_in);
EXIT WHEN NVL(v_pos,0) = 0;
nt_return.EXTEND;
nt_return(nt_return.LAST) := TRIM(SUBSTR(v_wkg_str,1,v_pos-1));
v_wkg_str := SUBSTR(v_wkg_str,v_pos+1);
END LOOP;
RETURN nt_return;
END string_to_table;
--------------------------------------------------------------
FUNCTION parse (
depth_in IN PLS_INTEGER DEFAULT 2
) RETURN VARCHAR2 IS
v_call_stack VARCHAR2(4096);
nt_stack_lines ntt_varchar2;
c_recsep CONSTANT VARCHAR2(1) := CHR(10);
c_headlines CONSTANT PLS_INTEGER := 3;
BEGIN
/* Get the call stack, removing the trailing newline... */
v_call_stack := RTRIM(DBMS_UTILITY.FORMAT_CALL_STACK, c_recsep);
/* Turn the call stack into a collection of lines... */
nt_stack_lines := string_to_table(v_call_stack, c_recsep);
/* Return the depth required (ignoring the header lines)... */
RETURN nt_stack_lines(depth_in + c_headlines);
EXCEPTION
WHEN SUBSCRIPT_BEYOND_COUNT THEN
RETURN NULL;
END parse;
--------------------------------------------------------------
FUNCTION caller (
depth_in IN PLS_INTEGER DEFAULT 3
) RETURN VARCHAR2 IS
v_callinfo VARCHAR2(255);
v_proginfo VARCHAR2(128);
v_lineinfo PLS_INTEGER;
v_return VARCHAR2(128);
c_colsep CONSTANT VARCHAR2(2) := ' '; -- two spaces
c_no_stack CONSTANT VARCHAR2(32) := 'Caller information not available';
BEGIN
/* Get the call information from the call stack... */
v_callinfo := stk.parse(depth_in);
/* Strip out the program and line number... */
IF v_callinfo IS NOT NULL THEN
v_proginfo := TRIM(SUBSTR(v_callinfo, INSTR(v_callinfo, c_colsep, -1) + LENGTH(c_colsep)));
v_lineinfo := TO_NUMBER(TRIM(SUBSTR(v_callinfo, INSTR(v_callinfo, c_colsep),
INSTR(v_callinfo, c_colsep || v_proginfo) -
INSTR(v_callinfo, c_colsep))));
v_return := v_proginfo ||', line '|| NVL(TO_CHAR(v_lineinfo), '<none>');
ELSE
v_return := c_no_stack;
END IF;
RETURN v_return;
END caller;
--------------------------------------------------------------
FUNCTION whoami RETURN VARCHAR2 AS
v_callinfo VARCHAR2(255);
v_program VARCHAR2(128);
c_anonymous CONSTANT VARCHAR2(15) := 'anonymous block';
c_colsep CONSTANT VARCHAR2(2) := ' '; -- one space
BEGIN
/* Get the call information from the call stack... */
v_callinfo := stk.parse(3);
/* If an anonymous block, then return as such, else derive the program name... */
IF INSTR(v_callinfo, c_anonymous) > 0 THEN
v_program := '<' || c_anonymous || '>';
ELSE
v_program := TRIM(SUBSTR(v_callinfo, INSTR(v_callinfo, c_colsep, -1) + LENGTH(c_colsep)));
END IF;
RETURN v_program;
END whoami;
END stk;
/
CREATE OR REPLACE PUBLIC SYNONYM stk FOR stk;
GRANT EXECUTE ON stk TO PUBLIC;