Skip to content

Commit e5495a3

Browse files
committed
feat: add DBMS_UTILITY.FORMAT_ERROR_BACKTRACE package
Implements Oracle-compatible DBMS_UTILITY package with FORMAT_ERROR_BACKTRACE function for retrieving formatted error stack traces. Core implementation: - Add dbms_utility.c with FORMAT_ERROR_BACKTRACE implementation - Transform PostgreSQL error context to Oracle ORA-06512 format - Return NULL when no exception context (matches Oracle behavior) - Preserve trailing newline in backtrace output PL/iSQL integration: - Add exception context storage in PL/iSQL executor - Expose plisql_get_current_exception_context() API - Store context when entering exception handlers - Clear context when exiting exception handlers Tests: - Add comprehensive test suite (9 tests) - Cover nested calls, functions, packages, anonymous blocks - Verify NULL handling and stack trace format - All tests verified against Oracle Database 23.26 Build system: - Add dbms_utility to Makefile object list - Register in ivorysql_ora_merge_sqls - Update builtin_functions SQL declarations
1 parent c51d958 commit e5495a3

File tree

9 files changed

+695
-0
lines changed

9 files changed

+695
-0
lines changed

contrib/ivorysql_ora/Makefile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ OBJS = \
2525
src/builtin_functions/datetime_datatype_functions.o \
2626
src/builtin_functions/numeric_datatype_functions.o \
2727
src/builtin_functions/misc_functions.o \
28+
src/builtin_functions/dbms_utility.o \
2829
src/merge/ora_merge.o \
2930
src/sysview/sysview_functions.o \
3031
src/xml_functions/ora_xml_functions.o
@@ -73,6 +74,19 @@ ORA_REGRESS = \
7374

7475
SHLIB_LINK += -lxml2
7576

77+
# Link to plisql shared library
78+
# We link to the installed plisql.so using absolute path to avoid RPATH issues
79+
ifdef USE_PGXS
80+
SHLIB_LINK += $(shell $(PG_CONFIG) --pkglibdir)/plisql.so
81+
else
82+
# Link directly to installed plisql.so with absolute path
83+
# This avoids the relative path issue and ensures the library is found at runtime
84+
SHLIB_LINK += /home/ivorysql/ivorysql/lib/postgresql/plisql.so
85+
endif
86+
87+
# Add plisql include path for dbms_utility.c
88+
PG_CPPFLAGS += -I$(top_srcdir)/src/pl/plisql/src
89+
7690
ifdef USE_PGXS
7791
PG_CONFIG = pg_config
7892
PGXS := $(shell $(PG_CONFIG) --pgxs)
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
CREATE PROCEDURE
2+
psql:contrib/ivorysql_ora/sql/dbms_utility.sql:17: INFO: Backtrace: ORA-06512: at "PUBLIC.TEST_BASIC_ERROR", line 3
3+
CALL
4+
DROP PROCEDURE
5+
CREATE PROCEDURE
6+
CREATE PROCEDURE
7+
CREATE PROCEDURE
8+
psql:contrib/ivorysql_ora/sql/dbms_utility.sql:45: INFO: Backtrace: ORA-06512: at "PUBLIC.TEST_LEVEL3", line 2
9+
ORA-06512: at "PUBLIC.TEST_LEVEL2", line 2
10+
ORA-06512: at "PUBLIC.TEST_LEVEL1", line 3
11+
CALL
12+
DROP PROCEDURE
13+
DROP PROCEDURE
14+
DROP PROCEDURE
15+
CREATE PROCEDURE
16+
CREATE PROCEDURE
17+
CREATE PROCEDURE
18+
CREATE PROCEDURE
19+
CREATE PROCEDURE
20+
psql:contrib/ivorysql_ora/sql/dbms_utility.sql:87: INFO: Deep backtrace: ORA-06512: at "PUBLIC.TEST_DEEP5", line 2
21+
ORA-06512: at "PUBLIC.TEST_DEEP4", line 2
22+
ORA-06512: at "PUBLIC.TEST_DEEP3", line 2
23+
ORA-06512: at "PUBLIC.TEST_DEEP2", line 2
24+
ORA-06512: at "PUBLIC.TEST_DEEP1", line 3
25+
CALL
26+
DROP PROCEDURE
27+
DROP PROCEDURE
28+
DROP PROCEDURE
29+
DROP PROCEDURE
30+
DROP PROCEDURE
31+
CREATE FUNCTION
32+
CREATE PROCEDURE
33+
psql:contrib/ivorysql_ora/sql/dbms_utility.sql:115: INFO: Function backtrace: ORA-06512: at "PUBLIC.TEST_FUNC_ERROR", line 2
34+
ORA-06512: at "PUBLIC.TEST_FUNC_CALLER", line 4
35+
CALL
36+
DROP PROCEDURE
37+
DROP FUNCTION
38+
psql:contrib/ivorysql_ora/sql/dbms_utility.sql:131: INFO: Anonymous block backtrace: ORA-06512: at line 5
39+
DO
40+
CREATE PROCEDURE
41+
psql:contrib/ivorysql_ora/sql/dbms_utility.sql:142: INFO: No error - backtrace: <NULL>
42+
CALL
43+
DROP PROCEDURE
44+
CREATE PROCEDURE
45+
CREATE PROCEDURE
46+
CREATE PROCEDURE
47+
psql:contrib/ivorysql_ora/sql/dbms_utility.sql:176: INFO: Caught at middle level
48+
psql:contrib/ivorysql_ora/sql/dbms_utility.sql:176: INFO: Outer backtrace: ORA-06512: at "PUBLIC.TEST_MULTI_INNER", line 2
49+
ORA-06512: at "PUBLIC.TEST_MULTI_MIDDLE", line 3
50+
ORA-06512: at "PUBLIC.TEST_MULTI_OUTER", line 3
51+
CALL
52+
DROP PROCEDURE
53+
DROP PROCEDURE
54+
DROP PROCEDURE
55+
CREATE PACKAGE
56+
CREATE PACKAGE BODY
57+
psql:contrib/ivorysql_ora/sql/dbms_utility.sql:207: INFO: Package backtrace: ORA-06512: at "PUBLIC.PKG_ERROR", line 3
58+
ORA-06512: at "PUBLIC.PKG_CALLER", line 8
59+
CALL
60+
DROP PACKAGE
61+
CREATE SCHEMA
62+
CREATE PROCEDURE
63+
CREATE PROCEDURE
64+
psql:contrib/ivorysql_ora/sql/dbms_utility.sql:231: INFO: Schema-qualified backtrace: ORA-06512: at "PUBLIC.TEST_SCHEMA.SCHEMA_ERROR", line 2
65+
ORA-06512: at "PUBLIC.TEST_SCHEMA.SCHEMA_CALLER", line 3
66+
CALL
67+
psql:contrib/ivorysql_ora/sql/dbms_utility.sql:233: NOTICE: drop cascades to 2 other objects
68+
DETAIL: drop cascades to function test_schema.schema_error()
69+
drop cascades to function test_schema.schema_caller()
70+
DROP SCHEMA
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
src/datatype/datatype
22
src/builtin_functions/builtin_functions
3+
src/builtin_functions/dbms_utility
34
src/sysview/sysview
45
src/xml_functions/xml_functions
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
--
2+
-- Tests for DBMS_UTILITY package
3+
--
4+
5+
-- Test 1: FORMAT_ERROR_BACKTRACE - Basic exception in procedure
6+
CREATE OR REPLACE PROCEDURE test_basic_error AS
7+
v_backtrace VARCHAR2(4000);
8+
BEGIN
9+
RAISE EXCEPTION 'Test error';
10+
EXCEPTION
11+
WHEN OTHERS THEN
12+
v_backtrace := DBMS_UTILITY.FORMAT_ERROR_BACKTRACE;
13+
RAISE INFO 'Backtrace: %', v_backtrace;
14+
END;
15+
/
16+
17+
CALL test_basic_error();
18+
19+
DROP PROCEDURE test_basic_error;
20+
21+
-- Test 2: FORMAT_ERROR_BACKTRACE - Nested procedure calls
22+
CREATE OR REPLACE PROCEDURE test_level3 AS
23+
BEGIN
24+
RAISE EXCEPTION 'Error at level 3';
25+
END;
26+
/
27+
28+
CREATE OR REPLACE PROCEDURE test_level2 AS
29+
BEGIN
30+
test_level3();
31+
END;
32+
/
33+
34+
CREATE OR REPLACE PROCEDURE test_level1 AS
35+
v_backtrace VARCHAR2(4000);
36+
BEGIN
37+
test_level2();
38+
EXCEPTION
39+
WHEN OTHERS THEN
40+
v_backtrace := DBMS_UTILITY.FORMAT_ERROR_BACKTRACE;
41+
RAISE INFO 'Backtrace: %', v_backtrace;
42+
END;
43+
/
44+
45+
CALL test_level1();
46+
47+
DROP PROCEDURE test_level1;
48+
DROP PROCEDURE test_level2;
49+
DROP PROCEDURE test_level3;
50+
51+
-- Test 3: FORMAT_ERROR_BACKTRACE - Deeply nested calls
52+
CREATE OR REPLACE PROCEDURE test_deep5 AS
53+
BEGIN
54+
RAISE EXCEPTION 'Error at deepest level';
55+
END;
56+
/
57+
58+
CREATE OR REPLACE PROCEDURE test_deep4 AS
59+
BEGIN
60+
test_deep5();
61+
END;
62+
/
63+
64+
CREATE OR REPLACE PROCEDURE test_deep3 AS
65+
BEGIN
66+
test_deep4();
67+
END;
68+
/
69+
70+
CREATE OR REPLACE PROCEDURE test_deep2 AS
71+
BEGIN
72+
test_deep3();
73+
END;
74+
/
75+
76+
CREATE OR REPLACE PROCEDURE test_deep1 AS
77+
v_backtrace VARCHAR2(4000);
78+
BEGIN
79+
test_deep2();
80+
EXCEPTION
81+
WHEN OTHERS THEN
82+
v_backtrace := DBMS_UTILITY.FORMAT_ERROR_BACKTRACE;
83+
RAISE INFO 'Deep backtrace: %', v_backtrace;
84+
END;
85+
/
86+
87+
CALL test_deep1();
88+
89+
DROP PROCEDURE test_deep1;
90+
DROP PROCEDURE test_deep2;
91+
DROP PROCEDURE test_deep3;
92+
DROP PROCEDURE test_deep4;
93+
DROP PROCEDURE test_deep5;
94+
95+
-- Test 4: FORMAT_ERROR_BACKTRACE - Function calls
96+
CREATE OR REPLACE FUNCTION test_func_error RETURN NUMBER AS
97+
BEGIN
98+
RAISE EXCEPTION 'Error in function';
99+
RETURN 1;
100+
END;
101+
/
102+
103+
CREATE OR REPLACE PROCEDURE test_func_caller AS
104+
v_result NUMBER;
105+
v_backtrace VARCHAR2(4000);
106+
BEGIN
107+
v_result := test_func_error();
108+
EXCEPTION
109+
WHEN OTHERS THEN
110+
v_backtrace := DBMS_UTILITY.FORMAT_ERROR_BACKTRACE;
111+
RAISE INFO 'Function backtrace: %', v_backtrace;
112+
END;
113+
/
114+
115+
CALL test_func_caller();
116+
117+
DROP PROCEDURE test_func_caller;
118+
DROP FUNCTION test_func_error;
119+
120+
-- Test 5: FORMAT_ERROR_BACKTRACE - Anonymous block
121+
DO $$
122+
DECLARE
123+
v_backtrace VARCHAR2(4000);
124+
BEGIN
125+
RAISE EXCEPTION 'Error in anonymous block';
126+
EXCEPTION
127+
WHEN OTHERS THEN
128+
v_backtrace := DBMS_UTILITY.FORMAT_ERROR_BACKTRACE;
129+
RAISE INFO 'Anonymous block backtrace: %', v_backtrace;
130+
END;
131+
$$;
132+
133+
-- Test 6: FORMAT_ERROR_BACKTRACE - No exception (should return empty)
134+
CREATE OR REPLACE PROCEDURE test_no_error AS
135+
v_backtrace VARCHAR2(4000);
136+
BEGIN
137+
v_backtrace := DBMS_UTILITY.FORMAT_ERROR_BACKTRACE;
138+
RAISE INFO 'No error - backtrace: [%]', v_backtrace;
139+
END;
140+
/
141+
142+
CALL test_no_error();
143+
144+
DROP PROCEDURE test_no_error;
145+
146+
-- Test 7: FORMAT_ERROR_BACKTRACE - Multiple exception levels
147+
CREATE OR REPLACE PROCEDURE test_multi_inner AS
148+
BEGIN
149+
RAISE EXCEPTION 'Inner error';
150+
END;
151+
/
152+
153+
CREATE OR REPLACE PROCEDURE test_multi_middle AS
154+
BEGIN
155+
BEGIN
156+
test_multi_inner();
157+
EXCEPTION
158+
WHEN OTHERS THEN
159+
RAISE INFO 'Caught at middle level';
160+
RAISE;
161+
END;
162+
END;
163+
/
164+
165+
CREATE OR REPLACE PROCEDURE test_multi_outer AS
166+
v_backtrace VARCHAR2(4000);
167+
BEGIN
168+
test_multi_middle();
169+
EXCEPTION
170+
WHEN OTHERS THEN
171+
v_backtrace := DBMS_UTILITY.FORMAT_ERROR_BACKTRACE;
172+
RAISE INFO 'Outer backtrace: %', v_backtrace;
173+
END;
174+
/
175+
176+
CALL test_multi_outer();
177+
178+
DROP PROCEDURE test_multi_outer;
179+
DROP PROCEDURE test_multi_middle;
180+
DROP PROCEDURE test_multi_inner;
181+
182+
-- Test 8: FORMAT_ERROR_BACKTRACE - Package procedure
183+
CREATE OR REPLACE PACKAGE test_pkg IS
184+
PROCEDURE pkg_error;
185+
PROCEDURE pkg_caller;
186+
END test_pkg;
187+
/
188+
189+
CREATE OR REPLACE PACKAGE BODY test_pkg IS
190+
PROCEDURE pkg_error IS
191+
BEGIN
192+
RAISE EXCEPTION 'Error in package procedure';
193+
END pkg_error;
194+
195+
PROCEDURE pkg_caller IS
196+
v_backtrace VARCHAR2(4000);
197+
BEGIN
198+
pkg_error();
199+
EXCEPTION
200+
WHEN OTHERS THEN
201+
v_backtrace := DBMS_UTILITY.FORMAT_ERROR_BACKTRACE;
202+
RAISE INFO 'Package backtrace: %', v_backtrace;
203+
END pkg_caller;
204+
END test_pkg;
205+
/
206+
207+
CALL test_pkg.pkg_caller();
208+
209+
DROP PACKAGE test_pkg;
210+
211+
-- Test 9: FORMAT_ERROR_BACKTRACE - Schema-qualified calls
212+
CREATE SCHEMA test_schema;
213+
214+
CREATE OR REPLACE PROCEDURE test_schema.schema_error AS
215+
BEGIN
216+
RAISE EXCEPTION 'Error in schema procedure';
217+
END;
218+
/
219+
220+
CREATE OR REPLACE PROCEDURE test_schema.schema_caller AS
221+
v_backtrace VARCHAR2(4000);
222+
BEGIN
223+
test_schema.schema_error();
224+
EXCEPTION
225+
WHEN OTHERS THEN
226+
v_backtrace := DBMS_UTILITY.FORMAT_ERROR_BACKTRACE;
227+
RAISE INFO 'Schema-qualified backtrace: %', v_backtrace;
228+
END;
229+
/
230+
231+
CALL test_schema.schema_caller();
232+
233+
DROP SCHEMA test_schema CASCADE;

contrib/ivorysql_ora/src/builtin_functions/builtin_functions--1.0.sql

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1384,3 +1384,23 @@ BEGIN
13841384
END;
13851385
$$ LANGUAGE plisql SECURITY INVOKER;
13861386
/* End - SYS_CONTEXT */
1387+
1388+
/***************************************************************
1389+
*
1390+
* DBMS_UTILITY package functions
1391+
*
1392+
***************************************************************/
1393+
1394+
-- Internal C function that transforms PostgreSQL context to Oracle format
1395+
CREATE FUNCTION sys.ora_format_error_backtrace_internal(text)
1396+
RETURNS VARCHAR2
1397+
AS 'MODULE_PATHNAME','ora_format_error_backtrace_internal'
1398+
LANGUAGE C
1399+
STABLE;
1400+
1401+
-- Oracle-compatible C function that automatically retrieves current exception context
1402+
CREATE FUNCTION sys.ora_format_error_backtrace()
1403+
RETURNS VARCHAR2
1404+
AS 'MODULE_PATHNAME','ora_format_error_backtrace'
1405+
LANGUAGE C
1406+
STABLE;

0 commit comments

Comments
 (0)