Skip to content

Commit a4265c1

Browse files
author
Steven Feuerstein
authored
Create find-function-calls-in-sql.pls
1 parent 11a883a commit a4265c1

File tree

1 file changed

+193
-0
lines changed

1 file changed

+193
-0
lines changed
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
/*
2+
You can call your own (user-defined) functions in SQL. But you need to do so with care:
3+
* possible performance impact, due to context switches
4+
* possible read consistency issues, since SQL in a function called from SQL does not participate in "outer" SQL read consistency
5+
*/
6+
7+
ALTER SESSION SET plscope_settings='identifiers:all, statements:all'
8+
/
9+
10+
DROP TABLE my_data
11+
/
12+
13+
CREATE TABLE my_data (n NUMBER)
14+
/
15+
16+
CREATE OR REPLACE FUNCTION my_function1
17+
RETURN NUMBER
18+
AUTHID DEFINER
19+
IS
20+
BEGIN
21+
RETURN 1;
22+
END;
23+
/
24+
25+
CREATE OR REPLACE FUNCTION my_function2
26+
RETURN NUMBER
27+
AUTHID DEFINER
28+
IS
29+
BEGIN
30+
RETURN 1;
31+
END;
32+
/
33+
34+
CREATE OR REPLACE PROCEDURE my_procedure (n_in IN NUMBER)
35+
AUTHID DEFINER
36+
IS
37+
l_my_data my_data%ROWTYPE;
38+
BEGIN
39+
SELECT my_function1 ()
40+
INTO l_my_data
41+
FROM my_data
42+
WHERE n = n_in
43+
AND my_function2 () = 0
44+
AND n = (SELECT my_function1 () FROM DUAL);
45+
46+
SELECT COUNT (*)
47+
INTO l_my_data
48+
FROM my_data
49+
WHERE n = n_in;
50+
51+
UPDATE my_data
52+
SET n = my_function2 ()
53+
WHERE n = n_in;
54+
END;
55+
/
56+
57+
/* Run this query to see the full hierarchy of identifiers/statements */
58+
59+
WITH one_obj_name AS (SELECT 'MY_PROCEDURE' object_name FROM DUAL)
60+
SELECT plscope_type,
61+
usage_id,
62+
usage_context_id,
63+
LPAD (' ', 2 * (LEVEL - 1)) || usage || ' ' || name usages
64+
FROM (SELECT 'ID' plscope_type,
65+
ai.object_name,
66+
ai.usage usage,
67+
ai.usage_id,
68+
ai.usage_context_id,
69+
ai.TYPE || ' ' || ai.name name,
70+
ai.line,
71+
ai.col,
72+
signature
73+
FROM all_identifiers ai, one_obj_name
74+
WHERE ai.object_name = one_obj_name.object_name
75+
UNION ALL
76+
SELECT 'ST',
77+
st.object_name,
78+
st.TYPE,
79+
st.usage_id,
80+
st.usage_context_id,
81+
'STATEMENT',
82+
st.line,
83+
st.col,
84+
signature
85+
FROM all_statements st, one_obj_name
86+
WHERE st.object_name = one_obj_name.object_name)
87+
START WITH usage_context_id = 0
88+
CONNECT BY PRIOR usage_id = usage_context_id
89+
/
90+
91+
/*
92+
ST 7 2 SELECT - STATEMENT
93+
ID 8 7 REFERENCE - TABLE MY_DATA
94+
ID 9 7 REFERENCE - COLUMN N
95+
ID 10 7 REFERENCE - FORMAL IN N_IN
96+
ID 11 7 REFERENCE - COLUMN N
97+
ID 13 7 CALL - FUNCTION MY_FUNCTION1
98+
ID 14 7 CALL - FUNCTION MY_FUNCTION2
99+
ID 15 7 ASSIGNMENT - VARIABLE L_MY_DATA
100+
ID 16 15 CALL - FUNCTION MY_FUNCTION1
101+
*/
102+
103+
/* Now what I want to do is return a list of all SQL statements
104+
that contain within it a call to a function */
105+
106+
WITH my_prog_unit AS (SELECT USER owner, 'MY_PROCEDURE' object_name FROM DUAL),
107+
full_set
108+
AS (SELECT ai.usage,
109+
ai.usage_id,
110+
ai.usage_context_id,
111+
ai.TYPE,
112+
ai.name
113+
FROM all_identifiers ai, my_prog_unit
114+
WHERE ai.object_name = my_prog_unit.object_name
115+
AND ai.owner = my_prog_unit.owner
116+
UNION ALL
117+
SELECT st.TYPE,
118+
st.usage_id,
119+
st.usage_context_id,
120+
'type',
121+
'name'
122+
FROM all_statements st, my_prog_unit
123+
WHERE st.object_name = my_prog_unit.object_name
124+
AND st.owner = my_prog_unit.owner),
125+
dml_statements
126+
AS (SELECT st.owner,
127+
st.object_name,
128+
st.line,
129+
st.usage_id,
130+
st.TYPE
131+
FROM all_statements st, my_prog_unit
132+
WHERE st.object_name = my_prog_unit.object_name
133+
AND st.owner = my_prog_unit.owner
134+
AND st.TYPE IN ('SELECT', 'UPDATE', 'DELETE'))
135+
SELECT st.owner,
136+
st.object_name,
137+
st.line,
138+
st.TYPE,
139+
s.text
140+
FROM dml_statements st, all_source s
141+
WHERE ('CALL', 'FUNCTION') IN ( SELECT fs.usage, fs.TYPE
142+
FROM full_set fs
143+
CONNECT BY PRIOR fs.usage_id =
144+
fs.usage_context_id
145+
START WITH fs.usage_id = st.usage_id)
146+
AND st.line = s.line
147+
AND st.object_name = s.name
148+
AND st.owner = s.owner
149+
/
150+
151+
/* Across all program units, all schemas */
152+
153+
WITH full_set
154+
AS (SELECT ai.owner,
155+
ai.object_name,
156+
ai.usage,
157+
ai.usage_id,
158+
ai.usage_context_id,
159+
ai.TYPE,
160+
ai.name
161+
FROM all_identifiers ai
162+
UNION ALL
163+
SELECT st.owner,
164+
st.object_name,
165+
st.TYPE,
166+
st.usage_id,
167+
st.usage_context_id,
168+
'type',
169+
'name'
170+
FROM all_statements st),
171+
dml_statements
172+
AS (SELECT st.owner,
173+
st.object_name,
174+
st.line,
175+
st.usage_id,
176+
st.TYPE
177+
FROM all_statements st
178+
WHERE st.TYPE IN ('SELECT', 'UPDATE', 'DELETE'))
179+
SELECT st.owner,
180+
st.object_name,
181+
st.line,
182+
st.TYPE,
183+
s.text
184+
FROM dml_statements st, all_source s
185+
WHERE ('CALL', 'FUNCTION') IN ( SELECT fs.usage, fs.TYPE
186+
FROM full_set fs
187+
CONNECT BY PRIOR fs.usage_id =
188+
fs.usage_context_id
189+
START WITH fs.usage_id = st.usage_id)
190+
AND st.line = s.line
191+
AND st.object_name = s.name
192+
AND st.owner = s.owner
193+
/

0 commit comments

Comments
 (0)