How to retrieve output parameter from stored procedure in oracle - oracle

I have below stored procedure. It works fine. But I wanted to test it for error scenarios. Even when there is an error, the procedure executes successfully without showing the error message. When I enable the set serveroutput on, it shows the error message. But I want to capture the error message.
create or replace PROCEDURE COMP_JSON (
OUT_MESSAGE OUT VARCHAR2,
PNI_ID IN NUMBER
)
AS
CURSOR C1 IS SELECT 1 AS ID,TYPE_ID, COMP, TYPE, PREV_AMOUNT, CURR_AMOUNT FROM V_COMP_COST;
SECID VARCHAR2(100);
K NUMBER:= 0;
L NUMBER:= 1000;--Commit Interval
LRETVALUE VARCHAR2(200):='0';
V_TYPE_ID JSON_DATA.TYPE_ID%TYPE;
V_COMP JSON_DATA.COMP%TYPE;
V_TYPE JSON_DATA.TYPE%TYPE;
BEGIN
APEX_JSON.INITIALIZE_CLOB_OUTPUT;
/* Cost Comparison */
IF NVL(PNI_ID, 1) = 1
THEN
K := 0;
BEGIN
FOR I IN C1
LOOP
V_TYPE_ID := I.TYPE_ID;
V_COMP := I.COMP;
V_TYPE := I.TYPE;
APEX_JSON.OPEN_OBJECT;
APEX_JSON.WRITE('prevAmt',I.PREV_AMOUNT);
APEX_JSON.WRITE('currAmt',I.CURR_AMOUNT);
APEX_JSON.CLOSE_OBJECT;
INSERT INTO JSON_DATA
VALUES (I.ID,I.TYPE_ID,I.COMP,I.TYPE,APEX_JSON.GET_CLOB_OUTPUT);
/* Commit Interval */
K := K+1;
IF MOD(K,L) = 0
THEN
COMMIT;
END IF;
APEX_JSON.FREE_OUTPUT;
IF K > 5
THEN
RAISE_APPLICATION_ERROR(-20000, NULL);
END IF;
END LOOP;
EXCEPTION
WHEN OTHERS
THEN LRETVALUE := '-1,k:Problem in loading Data -' || SQLERRM || ' AT: [' || V_TYPE_ID || '] [' || V_COMP || '] [' || V_TYPE || ']';
END;
COMMIT;
IF LRETVALUE <> '0'
THEN
OUT_MESSAGE := LRETVALUE;
RETURN;
END IF;
END IF;
EXCEPTION
WHEN OTHERS
THEN DBMS_OUTPUT.PUT_LINE('ERROR MESSAGE' || SQLERRM);
END COMP_JSON;

You're using a nested block to throw your exception, but it will continue processing. The outbound variable "OUT_MESSAGE" should capture that value. Is it? if so, you can see what it is with this:
SQL> VAR ERR_MSG VARCHAR2;
SQL> EXEC COMP_JSON(:ERR_MSG, 5); --whatever you use for PNI_ID....
PL/SQL procedure successfully completed.
SQL> PRINT ERR_MSG;
If your program never throws an error, then OUT_MESSAGE will never be set, thus it will be null upon completion of the program.
If you are looking to throw an error from your program if your "nested block" throws an error, then you need to re-raise the exception so that the outer exception catches it:
IF K > 5
THEN
RAISE_APPLICATION_ERROR(-20000, NULL);
END IF;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
LRETVALUE := '-1,k:Problem in loading Data -' || SQLERRM || ' AT: [' || V_TYPE_`ID || '] [' || V_COMP || '] [' || V_TYPE || ']';
RAISE_APPLICATION_ERROR(-20000, LRETVALUE );
END;

If you need the caller to raise an exception, you need that your procedure propagates it to the external.
For example:
SQL> create or replace procedure raiseException(p in number) is
2 n number;
3 begin
4 n := p/0;
5 exception
6 when others then
7 dbms_output.put_line('Error message: ' || sqlerrm);
8 raise;
9 end;
10 /
Procedure created.
SQL> create or replace procedure procedureCall is
2 begin
3 raiseException(10);
4 end;
5 /
Procedure created.
The first procedure will print a message and raise an exception; in this way, we have the error message in output and an exception:
SQL> exec procedureCall
Error message: ORA-01476: divisor is equal to zero
BEGIN procedureCall; END;
*
ERROR at line 1:
ORA-01476: divisor is equal to zero
ORA-06512: at "ALEK.RAISEEXCEPTION", line 8
ORA-06512: at "ALEK.PROCEDURECALL", line 3
ORA-06512: at line 1
If you remove the RAISE, the exception will be handled and not propagated, thus giving no error:
SQL> create or replace procedure raiseException(p in number) is
2 n number;
3 begin
4 n := p/0;
5 exception
6 when others then
7 dbms_output.put_line('Error message: ' || sqlerrm);
8 end;
9 /
Procedure created.
SQL> exec procedureCall
Error message: ORA-01476: divisor is equal to zero
PL/SQL procedure successfully completed.

Related

Oracle stored procedure runtime error with pls 00103

(Update 2019/07/23) New way to call procedure
SET SERVEROUTPUT ON
declare
variable res sys_refcursor;
begin
my_schema.SP_READ_MEMBER('11223344', '1970/01/01', res);
EXCEPTION
WHEN OTHERS
THEN DBMS_OUTPUT.put_line ('ERROR ' || SQLERRM);
end;
/
Result
Error at line 2
ORA-06550: line 2, column 16:
PLS-00103: Encountered the symbol "SYS_REFCURSOR" when expecting one of the following:
:= . ( # % ; not null range default character
The symbol ":=" was substituted for "SYS_REFCURSOR" to continue.
(Original post)
I'm not really good on Oracle's Stored Procedure, so this error confused me much time. Had read 10 more threads on this site about PLS-00103. but none of them seems helped with my error.
Here's my Stored Procedure
create or replace procedure my_schema.SP_READ_MEMBER(keywordP in varchar2, birthdayP in varchar2, resultP out sys_refcursor)
is
v_prg_name varchar2(20) := 'SP_READ_MEMBER';
sys_sql varchar2(1000);
begin
Insertlog(SYSDATE, v_prg_name, '1.0 Start');
sys_sql := sys_sql || 'select a.no, a.name, a.id_no, to_char(a.birthday, ''yyyy/MM/dd'') as birthday, ''REGISTERED'' as type, email, mobile from rep a where 1=1 ';
if keywordP is not null then
sys_sql := sys_sql || ' and (a.no=''' || keywordP || ''' or a.name=''' || keywordP || ''' or a.id_no=''' || keywordP || ''') ';
end if;
if birthdayP is not null then
sys_sql := sys_sql || ' and a.birthday=to_date(''' || birthdayP || ''', ''yyyy/MM/dd'') ';
end if;
open resultP for sys_sql;
Insertlog(SYSDATE, v_prg_name, '2.0 Finished w/o error');
exception
when others then
declare
error_time VARCHAR2(30) := RTRIM(TO_CHAR(SYSDATE, 'YYYY/MM/DD, HH24:MI:SS'));
error_code NUMBER := SQLCODE;
error_msg VARCHAR2(300) := SQLERRM;
begin
rollback;
DBMS_OUTPUT.PUT_LINE(error_time || ',' || TO_CHAR(error_code) || ',' || error_msg);
Insertlog(SYSDATE, v_prg_name, error_msg || ', 3.0 ERROR, sql:' || sys_sql);
end;
end;
/
And run it in toad, with following script :
SET SERVEROUTPUT ON
declare
res varchar2(1000);
begin
call my_schema.SP_READ_MEMBER('11223344', '1970/01/01', res);
EXCEPTION
WHEN OTHERS
THEN DBMS_OUTPUT.put_line ('ERROR ' || SQLERRM);
end;
/
This error message really confused me much hours...
Error at line 2
ORA-06550: line 4, column 8:
PLS-00103: Encountered the symbol "my_schema" when expecting one of the following:
:= . ( # % ;
The symbol ":=" was substituted for "my_schema" to continue.
Now I'm stuck here, please gives some suggestions, really need this ...
PS: Got same error message while called from c#
You have ro remove the call; for example:
SQL> begin
2 call testProc;
3 end;
4 /
call testProc;
*
ERROR at line 2:
ORA-06550: line 2, column 10:
PLS-00103: Encountered the symbol "TESTPROC" when expecting one of the
following:
:= . ( # % ;
The symbol ":=" was substituted for "TESTPROC" to continue.
SQL> begin
2 testProc;
3 end;
4 /
PL/SQL procedure successfully completed.
Also, notice that your procedure has a sys_refcursor out parameter, but you call it by passing a varchar2.
As an aside, using a varchar2 to handle dates is not a good idea; the date type would be better.
As mentioned in the previous answer, There are several mistakes in calling the procedure itself.
Your code to call the procedure should look like the following:
SET SERVEROUTPUT ON
declare
res SYS_REFCURSOR; -- Changed data type of this variable
begin
my_schema.SP_READ_MEMBER('11223344', '1970/01/01', res); -- removed 'call'
EXCEPTION
WHEN OTHERS
THEN DBMS_OUTPUT.put_line ('ERROR ' || SQLERRM);
end;
/
Cheers!!

ORA 6502 character string buffer too small

I am a newbie in PL/SQL
I have an PL SQL. And im getting an error shown in the title. ORA 6502 character string buffer too small.
create or replace
PROCEDURE MailSender IS
tmpVar VARCHAR2(2048);
BEGIN
FOR cur_rec IN
(SELECT * FROM dom_email1 where rownum <= 50 and eto is not null ORDER BY eid asc)
LOOP
tmpVar := ltrim(cur_rec.ETO, ' ; ');
tmpVar := rtrim(tmpVar, '; ');
tmpVar := rtrim(tmpVar, ' ');
DOMSYS_EMAIL.SEND_EMAIL(msg_from => 'noreply#gmail.com'
, msg_tos => tmpVar
, msg_subject => cur_rec.SUBJ
, msg_text => cur_rec.MSG
, mailhost => '10.63.17.38');
UPDATE DOM_EMAIL1 SET eid='1' WHERE eid= cur_rec.EID;
END LOOP;
DELETE FROM DOM_EMAIL1 WHERE eid='1';
EXCEPTION
WHEN NO_DATA_FOUND THEN
NULL;
WHEN OTHERS THEN
-- Consider logging the error and then re-raise
RAISE;
END MailSender;
Issue is due to the size is not satisfied for any of the below variables/cursor value you are passing in your procedure
tmpVar
cur_rec.SUBJ
cur_rec.MSG
Add the below line in your procedure before send mail (DOMSYS_EMAIL.SEND_EMAIL) to validate the size of each value you passed and check whether it satisfies the parameter size limit of the DOMSYS_EMAIL.SEND_EMAIL procedure
dbms_output.put_line('tmpVar :' || length(tmpVar) ||' - '|| 'cur_rec.SUBJ :'|| length(cur_rec.SUBJ) ||' - '|| 'cur_rec.MSG :' || length(cur_rec.MSG));
For varchar2,you can update the size limit if required after validation

Trying to get the actual data that cause an exception

I have a procedure that takes an input of 2 Associative arrays and after some basic count checks, does a FORALL statement to insert the data into a table.
Here is the procedure:
PROCEDURE INSERT_RECS(P_PROD_TYP IN prod_type, P_PROD_ADD_PK IN prod_pk_type)
IS
uniq_key EXCEPTION;
PRAGMA EXCEPTION_INIT(uniq_key, -00001);
loc_cnt NUMBER;
BEGIN
IF P_PROD_TYP.COUNT = P_PROD_ADD_PK.COUNT THEN
FORALL i IN P_PROD_TYP.FIRST .. P_PROD_TYP.LAST
INSERT INTO product_table ( pk,
id,
created_by,
created_on,
last_chg_by,
last_chg_on)
VALUES (P_PROD_ADD_PK(i),
P_PROD_TYP(i).id,
P_PROD_TYP(i).created_by,
P_PROD_TYP(i).created_on,
NULL,
NULL);
END IF;
EXCEPTION
WHEN uniq_key THEN
loc_cnt := SQL%BULK_EXCEPTIONS.count;
FOR i IN 1 .. loc_cnt LOOP
dbms_output.put_line('EXCEPTION: Array Index: ' || SQL%BULK_EXCEPTIONS(i).error_index ||
' Message: ' || SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE) ||
' SQLERRM: ' || SQLERRM ||
' SQLCODE: ' || SQLCODE ||
' stack: ' || SYS.dbms_utility.format_call_stack);
END LOOP;
RETURN;
END;
What I would like is if I hit an exception, is there a way that I could have view of the record that is causing the issue, essentially the index in the associative array or at least have the SQL% info have the info.
I have look at the following:
http://www.dba-oracle.com/plsql/t_plsql_exceptions.htm
but this outputs the info about the column but that is not what I am after.
Not sure if really answers your query but you can use the loop variable i in exception block to display the content of the exception array in your case. See below an example procedure:
CREATE OR REPLACE PROCEDURE PROC1 (V_EMP_ID DBMS_SQL.NUMBER_TABLE)
IS
lv_error_string VARCHAR2(4000);
BEGIN
FORALL INDX IN V_EMP_ID.FIRST..V_EMP_ID.LAST SAVE EXCEPTIONS
UPDATE EMPLOYEES
---trying to rasie an exception by using a calculation
SET SALARY=SALARY * 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
WHERE ID_E= V_EMP_ID(INDX);
EXCEPTION
WHEN OTHERS
THEN
FOR i IN 1 .. SQL%BULK_EXCEPTIONS.COUNT
LOOP
---Am printing the value of the exception array.
dbms_output.put_line('exception Raised for record' ||V_EMP_ID(i));
END LOOP;
END;
/
Ouput:
SQL> DECLARE
empid DBMS_SQL.NUMBER_TABLE;
BEGIN
empid (1) := 1;
empid (2) := 9;
PROC1 (empid);
END;
/
exception Raised for record 1
PL/SQL procedure successfully completed.

Ora 01403 when try to insert data into oracle table

I have the following trigger
CREATE OR REPLACE TRIGGER L_BIUR_G_LAY
BEFORE INSERT OR UPDATE ON G_LAY
FOR EACH ROW
When (new.g_roo is not null)
DECLARE
x number(1);
stmt varchar(255);
BEGIN
FOR I IN (SELECT DISTINCT G_TAB FROM G_LEG)
LOOP
stmt := 'select distinct g_lind from ' || i.g_tab || ' where g_roo = ' || :new.g_roo;
Execute immediate stmt into x;
IF (x<>0) THEN
RAISE_APPLICATION_ERROR(-2001, 'G_ROO cannot be inserted where G_LIND IS NOT ZERO');
END IF;
END LOOP;
END;
/
and when I do
insert into G_LAY (G_OGCS, G_OGC, G_ROO, G_NM, G_TI, G_AB, G_DATE)
(select G_LAY_SEQ.NEXTVAL, 1, G_ROO, G_LGNDIT, G_UNE, 'Pipe Data Long - ' || G_UR, sysdate
from G_DTABLE where G_LIND = 0);
I get the following error
Error report:
SQL Error: ORA-01403: no data found
ORA-06512: at "L_BIUR_G_LAY", line 10
ORA-04088: error during execution of trigger 'G_LAY'
01403. 00000 - "no data found"
Any help would be greatly appreciated. It tried PRAGMA AUTONOMOUS_TRANSACTION after Declare in my trigger but it didn't help me
The problem is not with your INSERT statement. The problem occurs when the dynamically-built SELECT statement in the trigger is executed - no data is found so an ORA-01403 is raised. It looks to me like the easiest thing to do would be to do a SELECT COUNT(...):
CREATE OR REPLACE TRIGGER L_BIUR_G_LAY
BEFORE INSERT OR UPDATE ON G_LAY
FOR EACH ROW
When (new.g_rowno is not null)
DECLARE
x number;
stmt varchar(255);
BEGIN
FOR I IN (SELECT DISTINCT G_DISPCNTRLTAB FROM G_LEG) LOOP
stmt := 'select COUNT(*) from ' || i.g_dispcntrltab ||
' where g_rowno = ' || :new.g_rowno ||
' and g_lind <> 0';
Execute immediate stmt into x;
IF x <> 0 THEN
RAISE_APPLICATION_ERROR(-20001, 'G_RWNO cannot be inserted where G_LIND IS NOT ZERO');
END IF;
END LOOP;
END L_BIUR_G_LAY;
I also changed the error number which is raised as -2001 is not in the range of errors which can be raised using RAISE_APPLICATION_ERROR (the valid range is -20000 to -20999).
Share and enjoy.

Stored procedure exception handling

SQL> DECLARE
2 TotalUpd NUMBER(36) := 0;
3 BEGIN
4 dbms_output.put_line ('Job Start time............... : ' || to_char(SYSDATE, ' hh24:mi:ss'));
5 UPDATE Asset SET _status = 'PROGRESS' WHERE status is null;
6 TotalUpd := SQL%ROWCOUNT;
7 dbms_output.put_line('Total Records Updated. : ' || TotalUpd);
8 COMMIT;
9 EXCEPTION
10 WHEN NO_DATA_FOUND THEN
11 dbms_output.put_line ('No more data to update.');
12 WHEN OTHERS THEN
13 dbms_output.put_line ('Error while status as SUCCESS ');
14 END ;
15 /
The result for the above procedure is
Job Start time............... : 04:41:41
Total Records Updated. : 0
But my expected result is "No more row to be updated" must be printed,since i have truncated the table Asset.Please tell where I went wrong in this.
The NO_DATA_FOUND error is not thrown in update statements.
It is thrown in select into statements if the select statement would return nothing.
See also Tahiti on select into under select_item: *If the SELECT INTO statement returns no rows, PL/SQL raises the predefined exception NO_DATA_FOUND.*
Oracle does not consider it an exception if an update statement does not update anything, hence no exception is thrown. However, if a select into statement cannot fill the variables, it is considered an error (and therefore in this case the NO_DATA_EXCEPTION is thrown(
it is as simple as the update does not geneate an error if there is no data.
you need to look at the value of TotalUpd if you want to control the flow of your code
DECLARE
TotalUpd NUMBER(36) := 0;
BEGIN
dbms_output.put_line ('Job Start time............... : '
|| TO_CHAR(SYSDATE, ' hh24:mi:ss'));
UPDATE Asset SET _status = 'PROGRESS' WHERE status IS null;
TotalUpd := SQL%ROWCOUNT;
IF TotalUpd = 0 THEN
dbms_output.put_line ('No more data to update.');
ELSE
dbms_output.put_line('Total Records Updated. : '
|| TotalUpd);
END IF;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line ('Error while status as SUCCESS ');
END;
NO_DATA_FOUND is thrown if a select into does not return any row, not if no rows were updated after an update statement.
I suggest you move your logic for handling this exception after the update itself:
IF (SQL%ROWCOUNT = 0) THEN
dbms_output.put_line ('No more data to update.');
Think NO_DATA_FOUND exception is only raised by a SELECT statement which you aren't using. Try testing SQL%COUNT and output as required.

Resources