Scope
Following the previous post we will continue our investigations concerning the modifications of a big package.
Debugging a big package can be a challenging task. Of course you could use a debugging program, but in our case we have to modify some expressions in order to get the expected results. For this purpose we will use instead a custom tracing procedure.
Custom tracing procedure
You will find below a custom tracing procedure that we will use:
-- =======================================================================
-- Procedure : my_tracing
-- Description : Custom tracing program
-- Parameters : in_message, in_unit, in_line, in_sub_unit, in_type
-- Author : Arnaud Fargues
-- Creation : 17.12.2017
-- Modifications : 07.01.2018
-- =======================================================================
PROCEDURE my_tracing (
in_message IN VARCHAR2,
in_unit IN VARCHAR2 DEFAULT NULL,
in_line IN NUMBER DEFAULT NULL,
in_sub_unit IN VARCHAR2 DEFAULT NULL,
in_type IN CHAR DEFAULT 'I')
AS
l_message VARCHAR2(255);
BEGIN
IF NVL($$is_tracing,FALSE)
THEN
IF in_unit IS NOT NULL
THEN
l_message := '{' || in_unit;
IF in_sub_unit IS NOT NULL
THEN
l_message := l_message || '/' || in_sub_unit || '}';
ELSE
l_message := l_message || '}';
END IF;
ELSIF in_sub_unit IS NOT NULL
THEN
l_message := '{' || in_sub_unit || '}';
ELSE
l_message := '{}';
END IF;
DBMS_OUTPUT.PUT_LINE('(' || in_type || ')' || in_line || l_message || ':' || in_message);
END IF;
END my_tracing;
A typical call of this function is:
...
my_tracing('condition1',$$PLSQL_UNIT,$$PLSQL_LINE,'function51');
...
You will find a description of the different parameters below:
- in_message : message that we want to display,
- in_unit : PL/SQL current unit provided by the inquiry directive $$PLSQL_UNIT,
- in_line : source line number called by this procedure provided by the inquiry directive $$PLSQL_LINE,
- in_sub_unit : sub PL/SQL unit,
- in_type : information type – (I)nfo, (W)arning, (E)rror.
Remarks:
- We will use the inquiry directive $$is_tracing in order to trace or not the package,
- We have decided for this case to include the procedure my_tracing in the BIG_PACKAGE1 package body, but this procedure could be integrated in a general purpose package.
You will find below the modified package corresponding to the “Fourth approach – Conditional compilation”:
CREATE OR REPLACE PACKAGE BODY DEV3.BIG_PACKAGE1 AS
-- =======================================================================
-- Procedure : my_tracing
-- Description : Custom tracing program
-- Parameters : in_message, in_unit, in_line, in_sub_unit, in_type
-- Author : Arnaud Fargues
-- Creation : 17.12.2017
-- Modifications : 07.01.2018
-- =======================================================================
PROCEDURE my_tracing (
in_message IN VARCHAR2,
in_unit IN VARCHAR2 DEFAULT NULL,
in_line IN NUMBER DEFAULT NULL,
in_sub_unit IN VARCHAR2 DEFAULT NULL,
in_type IN CHAR DEFAULT 'I')
AS
l_message VARCHAR2(255);
BEGIN
IF NVL($$is_tracing,FALSE)
THEN
IF in_unit IS NOT NULL
THEN
l_message := '{' || in_unit;
IF in_sub_unit IS NOT NULL
THEN
l_message := l_message || '/' || in_sub_unit || '}';
ELSE
l_message := l_message || '}';
END IF;
ELSIF in_sub_unit IS NOT NULL
THEN
l_message := '{' || in_sub_unit || '}';
ELSE
l_message := '{}';
END IF;
DBMS_OUTPUT.PUT_LINE('(' || in_type || ')' || in_line || l_message || ':' || in_message);
END IF;
END my_tracing;
...
-- =======================================================================
-- function : function51 lvl:1
-- =======================================================================
FUNCTION function51(in_param NUMBER) RETURN NUMBER AS
l_GogRtbjjixylNzMdLPb NUMBER;
BEGIN
l_GogRtbjjixylNzMdLPb := in_param;
IF in_param = 9878 AND $$function51_condition1 -- modified
THEN
l_GogRtbjjixylNzMdLPb := l_GogRtbjjixylNzMdLPb + 7684;
my_tracing('condition1',$$PLSQL_UNIT,$$PLSQL_LINE,'function51');
ELSE
l_GogRtbjjixylNzMdLPb := l_GogRtbjjixylNzMdLPb - 448;
END IF;
l_GogRtbjjixylNzMdLPb := function14(l_GogRtbjjixylNzMdLPb);
IF in_param = 5554
THEN
l_GogRtbjjixylNzMdLPb := l_GogRtbjjixylNzMdLPb + 8352;
ELSE
l_GogRtbjjixylNzMdLPb := l_GogRtbjjixylNzMdLPb - 3003;
END IF;
l_GogRtbjjixylNzMdLPb := function149(l_GogRtbjjixylNzMdLPb);
IF in_param = 458 AND $$function51_condition2 -- modified
THEN
l_GogRtbjjixylNzMdLPb := l_GogRtbjjixylNzMdLPb + 7434;
my_tracing('condition2',$$PLSQL_UNIT,$$PLSQL_LINE,'function51');
ELSE
l_GogRtbjjixylNzMdLPb := l_GogRtbjjixylNzMdLPb - 2579;
END IF;
l_GogRtbjjixylNzMdLPb := function3(l_GogRtbjjixylNzMdLPb);
IF in_param = 8905 AND $$function51_condition3 -- modified
THEN
l_GogRtbjjixylNzMdLPb := l_GogRtbjjixylNzMdLPb + 7326;
my_tracing('condition3',$$PLSQL_UNIT,$$PLSQL_LINE,'function51');
ELSE
l_GogRtbjjixylNzMdLPb := l_GogRtbjjixylNzMdLPb - 6456;
END IF;
l_GogRtbjjixylNzMdLPb := function149(l_GogRtbjjixylNzMdLPb);
IF in_param = 9569 AND $$function51_condition4 -- modified
THEN
l_GogRtbjjixylNzMdLPb := l_GogRtbjjixylNzMdLPb + 1804;
my_tracing('condition4',$$PLSQL_UNIT,$$PLSQL_LINE,'function51');
ELSE
l_GogRtbjjixylNzMdLPb := l_GogRtbjjixylNzMdLPb - 4303;
END IF;
l_GogRtbjjixylNzMdLPb := function29(l_GogRtbjjixylNzMdLPb);
...
RETURN l_GARQUWfazCmqmeKNsNRQ;
END function175;
END BIG_PACKAGE1 ;
/
We will set the different inquiry directives and then recompile the package body:
DEV3@pdb1> ALTER SESSION SET PLSQL_CCFLAGS = 'is_tracing:TRUE,function51_condition1:FALSE,function51_condition2:TRUE,function51_condition3:FALSE,function51_condition4:TRUE';
Session altered.
DEV3@pdb1> ALTER PACKAGE DEV3.BIG_PACKAGE1 COMPILE BODY;
Package body altered.
We will then execute the function51 as shown below:
DEV3@pdb1> SET SERVEROUTPUT ON
DEV3@pdb1> DECLARE
2 l_return NUMBER;
3 BEGIN
4
5 l_return := DEV3.BIG_PACKAGE1.FUNCTION51(458);
6
7 DBMS_OUTPUT.PUT_LINE('l_return:' || TO_CHAR(l_return));
8
9 END;
10 /
(I)18119{BIG_PACKAGE1/function51}:condition2
l_return:-515621871
PL/SQL procedure successfully completed.
DEV3@pdb1> DECLARE
2 l_return NUMBER;
3 BEGIN
4
5 l_return := DEV3.BIG_PACKAGE1.FUNCTION51(9569);
6
7 DBMS_OUTPUT.PUT_LINE('l_return:' || TO_CHAR(l_return));
8
9 END;
10 /
(I)18135{BIG_PACKAGE1/function51}:condition4
l_return:-515616666
PL/SQL procedure successfully completed.
Update 18.02.2018
The procedure my_tracing is usefull nevertheless the call parameters are not convenient because you have to indicate each time the parameters in_unit ($$PLSQL_UNIT), in_line ($$PLSQL_LINE) and in_sub_unit.
Since the Oracle 12cR1 release there is a new PL/SQL package UTL_CALL_STACK which is an enhancement of the DBMS_UTILITY.FORMAT_CALL_STACK package. In order to replace the parameters in_unit,in_line and in_sub_unit we will use the functions UTL_CALL_STACK.UNIT_LINE and UTL_CALL_STACK.SUBPROGRAM.
You will find below the modified my_tracing procedure:
-- =======================================================================
-- Procedure : my_tracing
-- Description : Custom tracing program
-- Parameters : in_message, in_unit, in_line, in_sub_unit, in_type
-- Author : Arnaud Fargues
-- Creation : 17.12.2017
-- Modifications : 07.01.2018
-- 11.02.2018 Remove in_line, in_unit and in_sub_unit parameters
-- =======================================================================
PROCEDURE my_tracing (
in_message IN VARCHAR2,
in_type IN CHAR DEFAULT 'I')
AS
l_message VARCHAR2(255);
l_line NUMBER;
l_unit VARCHAR2(255);
BEGIN
IF NVL($$is_tracing,FALSE)
THEN
l_line := UTL_CALL_STACK.UNIT_LINE(2);
l_unit := UTL_CALL_STACK.CONCATENATE_SUBPROGRAM(UTL_CALL_STACK.SUBPROGRAM(2));
l_message := '{' || l_unit || '}';
DBMS_OUTPUT.PUT_LINE('(' || in_type || ')' || l_line || l_message || ':' || in_message);
END IF;
END my_tracing;
Remarks:
- Each function UTL_CALL_STACK.UNIT_LINE and UTL_CALL_STACK.SUBPROGRAM use a parameter which is the depth level in the call stack. The first level represents the my_tracing procedure level, the second level represents the level of the unit that have called the my_tracing procedure. In our case we are interested by the level 2,
- The function UTL_CALL_STACK.CONCATENATE_SUBPROGRAM returns the called path of the different units e.g. unit1.unit2.unit3.
You will find below the modified package:
CREATE OR REPLACE PACKAGE BODY DEV3.BIG_PACKAGE1 AS
-- =======================================================================
-- Procedure : my_tracing
-- Description : Custom tracing program
-- Parameters : in_message, in_unit, in_line, in_sub_unit, in_type
-- Author : Arnaud Fargues
-- Creation : 17.12.2017
-- Modifications : 07.01.2018
-- 11.02.2018 Remove in_line, in_unit and in_sub_unit parameters
-- =======================================================================
PROCEDURE my_tracing (
in_message IN VARCHAR2,
in_type IN CHAR DEFAULT 'I')
AS
l_message VARCHAR2(255);
l_line NUMBER;
l_unit VARCHAR2(255);
BEGIN
IF NVL($$is_tracing,FALSE)
THEN
l_line := UTL_CALL_STACK.UNIT_LINE(2);
l_unit := UTL_CALL_STACK.CONCATENATE_SUBPROGRAM(UTL_CALL_STACK.SUBPROGRAM(2));
l_message := '{' || l_unit || '}';
DBMS_OUTPUT.PUT_LINE('(' || in_type || ')' || l_line || l_message || ':' || in_message);
END IF;
END my_tracing;
...
-- =======================================================================
-- function : function51 lvl:1
-- =======================================================================
FUNCTION function51(in_param NUMBER) RETURN NUMBER AS
l_GogRtbjjixylNzMdLPb NUMBER;
BEGIN
l_GogRtbjjixylNzMdLPb := in_param;
IF in_param = 9878 AND $$function51_condition1 -- modified
THEN
l_GogRtbjjixylNzMdLPb := l_GogRtbjjixylNzMdLPb + 7684;
my_tracing('condition1');
ELSE
l_GogRtbjjixylNzMdLPb := l_GogRtbjjixylNzMdLPb - 448;
END IF;
l_GogRtbjjixylNzMdLPb := function14(l_GogRtbjjixylNzMdLPb);
IF in_param = 5554
THEN
l_GogRtbjjixylNzMdLPb := l_GogRtbjjixylNzMdLPb + 8352;
ELSE
l_GogRtbjjixylNzMdLPb := l_GogRtbjjixylNzMdLPb - 3003;
END IF;
l_GogRtbjjixylNzMdLPb := function149(l_GogRtbjjixylNzMdLPb);
IF in_param = 458 AND $$function51_condition2 -- modified
THEN
l_GogRtbjjixylNzMdLPb := l_GogRtbjjixylNzMdLPb + 7434;
my_tracing('condition2');
ELSE
l_GogRtbjjixylNzMdLPb := l_GogRtbjjixylNzMdLPb - 2579;
END IF;
l_GogRtbjjixylNzMdLPb := function3(l_GogRtbjjixylNzMdLPb);
IF in_param = 8905 AND $$function51_condition3 -- modified
THEN
l_GogRtbjjixylNzMdLPb := l_GogRtbjjixylNzMdLPb + 7326;
my_tracing('condition3');
ELSE
l_GogRtbjjixylNzMdLPb := l_GogRtbjjixylNzMdLPb - 6456;
END IF;
l_GogRtbjjixylNzMdLPb := function149(l_GogRtbjjixylNzMdLPb);
IF in_param = 9569 AND $$function51_condition4 -- modified
THEN
l_GogRtbjjixylNzMdLPb := l_GogRtbjjixylNzMdLPb + 1804;
my_tracing('condition4');
ELSE
l_GogRtbjjixylNzMdLPb := l_GogRtbjjixylNzMdLPb - 4303;
END IF;
l_GogRtbjjixylNzMdLPb := function29(l_GogRtbjjixylNzMdLPb);
...
RETURN l_GARQUWfazCmqmeKNsNRQ;
END function175;
END BIG_PACKAGE1 ;
/
We will set the different inquiry directives and then recompile the package body:
DEV3@pdb1> ALTER SESSION SET PLSQL_CCFLAGS = 'is_tracing:TRUE,function51_condition1:FALSE,function51_condition2:TRUE,function51_condition3:FALSE,function51_condition4:TRUE';
Session altered.
DEV3@pdb1> ALTER PACKAGE DEV3.BIG_PACKAGE1 COMPILE BODY;
Package body altered.
We will then execute then function51 as shown below:
DEV3@pdb1> SET SERVEROUTPUT ON
DEV3@pdb1>
DEV3@pdb1> DECLARE
2 l_return NUMBER;
3 BEGIN
4
5 l_return := DEV3.BIG_PACKAGE1.FUNCTION51(458);
6
7 DBMS_OUTPUT.PUT_LINE('l_return:' || TO_CHAR(l_return));
8
9 END;
10 /
(I)18107{BIG_PACKAGE1.FUNCTION51}:condition2
l_return:-515621871
PL/SQL procedure successfully completed.
DEV3@pdb1> SET SERVEROUTPUT ON
DEV3@pdb1>
DEV3@pdb1> DECLARE
2 l_return NUMBER;
3 BEGIN
4
5 l_return := DEV3.BIG_PACKAGE1.FUNCTION51(9569);
6
7 DBMS_OUTPUT.PUT_LINE('l_return:' || TO_CHAR(l_return));
8
9 END;
10 /
(I)18123{BIG_PACKAGE1.FUNCTION51}:condition4
l_return:-515616666
PL/SQL procedure successfully completed.