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