Procedure calling gone bad - Statement Ignored - oracle

I have the following procedure to insert users in a table:
CREATE OR REPLACE PROCEDURE ELR_ADD_USER
(I_NAME IN VARCHAR2,
I_MORADA IN VARCHAR2,
I_BIRTHDATE IN DATE,
I_COUNTRY IN VARCHAR2,
O_ID OUT NUMBER,
O_ERROR_MSG OUT VARCHAR2)
IS
ERROR_NULL EXCEPTION;
BEGIN
IF I_NAME IS NULL OR
I_MORADA IS NULL OR
I_BIRTHDATE IS NULL OR
I_COUNTRY IS NULL THEN
RAISE ERROR_NULL;
END IF;
O_ID := ELR_seq_USER_ID.nextval;
IF O_ID IS NULL
RAISE ERROR_NULL;
END IF;
INSERT INTO ELR_USERS
VALUES (O_ID, I_NOME, I_MORADA, I_BIRTHDATE, I_COUNTRY);
EXCEPTION
WHEN ERROR_NULL THEN
O_ERROR_MSG := 'NULL FIELDS';
WHEN OTHERS THEN
O_ERROR_MSG := 'UNEXPECTED ERROR: '|| sqlerrm;
END;
/
I think the procedure and it's syntax are correct. However when I'm trying to call it with:
DECLARE
P_NAME VARCHAR2(50);
P_MORADA VARCHAR2(50);
P_BIRTHDATE DATE;
P_COUNTRY VARCHAR2(20);
P_ID NUMBER(20);
P_ERROR_MSG VARCHAR2(4000);
BEGIN
ELR_ADD_USER('ED WARNER','CENAS Street',SYSDATE,
'China', P_ID, P_ERROR_MSG);
IF P_ERROR_MSG IS NOT NULL THEN
DBMS_OUTPUT.PUT_LINE('ERROR: '||P_ERROR_MSG);
END IF;
END;
/
I get the following message:
Is there something wrong with the calling or the procedure itself?

ORA-06550 followed by PLS-00905 is clearly a compilation error. The procedure is in INVALID state.
Recompile the procedure, and use SHOW ERRORS to get the complete error details.
SHOW ERROR PROCEDURE RMS_MM.ELR_ADD_USER or simply SHOW ERRORS
For example,
SQL> CREATE OR REPLACE PROCEDURE TestProc
2 AS
3 vnum number;
4 BEGIN
5 vnum := vAnotherNum;
6 END;
7 /
Warning: Procedure created with compilation errors.
SQL> execute TestProc();
BEGIN TestProc(); END;
*
ERROR at line 1:
ORA-06550: line 1, column 7:
PLS-00905: object EXAMPLE.TESTPROC is invalid
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
SQL> show error procedure TestProc;
Errors for PROCEDURE TESTPROC:
LINE/COL ERROR
-------- -----------------------------------------------------------------
5/1 PL/SQL: Statement ignored
5/9 PLS-00201: identifier 'VANOTHERNUM' must be declared

Related

ORACLE PL/SQL : How to pass an exception into a procedure

Is there a way to pass exception into a procedure to call "raise" after doing some actions to process exception. So that the outer code block will get the exact exception that was raised
Something like this:
begin
...
exception
when others then
error_handler( err );
end;
procedure error_handler ( err ) is
begin
/*
here some code to handle and log the exception...
*/
raise err;
end;
Or the only way is to pass SQLCODE and SQLERRM into the procedure and later call raise_application_error( SQLCODE, SQLERRM )?
If I understood you correctly, this is what you're asking.
Sample log table:
SQL> create table err_log
2 (program varchar2(30),
3 datum date,
4 sqlcode number
5 );
Table created.
Logging procedure should be an autonomous transaction so that you could commit in it, without affecting main transaction.
SQL> create or replace procedure error_handler
2 (p_program in varchar2, p_sqlcode in number)
3 is
4 pragma autonomous_transaction;
5 begin
6 insert into err_log (program, datum, sqlcode)
7 values (p_program, sysdate, p_sqlcode);
8 commit;
9 end;
10 /
Procedure created.
Another procedure (whose execution you're logging); it'll raise division by zero. See lines #8 and #9 which call the logging procedure and then just re-raise the error:
SQL> create or replace procedure p_test is
2 l_program varchar2(30) := 'P_TEST';
3 l_value number;
4 begin
5 l_value := 1 / 0;
6 exception
7 when others then
8 error_handler(l_program, sqlcode);
9 raise;
10 end p_test;
11 /
Procedure created.
OK, everything is set. Let's try it:
SQL> exec p_test;
BEGIN p_test; END;
*
ERROR at line 1:
ORA-01476: divisor is equal to zero --> this is result of RAISE in line #9
ORA-06512: at "SCOTT.P_TEST", line 9
ORA-06512: at "SCOTT.P_TEST", line 5
ORA-06512: at line 1
Log table contents:
SQL> select * from err_log;
PROGRAM DATUM SQLCODE
------------------------------ ------------------- ----------
P_TEST 01.11.2022 11:13:31 -1476
SQL>
You asked, literally:
How to pass an exception into a procedure?
You can't, as far as I can tell:
SQL> create or replace procedure error_handler_text
2 (p_err in exception) --> if this is what you asked
3 is
4 begin
5 null;
6 end;
7 /
Warning: Procedure created with compilation errors.
SQL> show err
Errors for PROCEDURE ERROR_HANDLER_TEXT:
LINE/COL ERROR
-------- -----------------------------------------------------------------
2/13 PLS-00103: Encountered the symbol "EXCEPTION" when expecting one
of the following:
out <an identifier> <a double-quoted delimited-identifier>
table columns long double ref char standard time timestamp
interval date binary national character nchar
The symbol "<an identifier> was inserted before "EXCEPTION" to
continue.
SQL>

Cursor as in parameter - refactoring a procedure

I have many functions similiar to this one:
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
PROCEDURE REP_HELPER1 (myIdx IN BINARY_INTEGER, from_d IN DATE, rep_table IN OUT rep_table_T) IS
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
CURSOR myCUR1 IS SELECT myField1,
myField2,
myField3,
myField4,
myField5,
myField6,
myField7,
myField8,
myField9,
myField10,
myField11,
myField12,
myField13,
myField14,
myField15,
myField16,
myField17,
myField18,
myField19,
myField20,
myField21,
myField22,
myField23,
myField24,
myField25,
myField26,
myField27,
myField28,
myField29,
myField30,
myField31
FROM myTable;
BEGIN
-- I wish to move the part below to different procedure
OPEN myCUR1;
FETCH myCUR1 INTO rep_table(myIdx).day1, rep_table(myIdx).day2, rep_table(myIdx).day3, rep_table(myIdx).day4, rep_table(myIdx).day5,
rep_table(myIdx).day6, rep_table(myIdx).day7, rep_table(myIdx).day8, rep_table(myIdx).day9, rep_table(myIdx).day10,
rep_table(myIdx).day11, rep_table(myIdx).day12, rep_table(myIdx).day13, rep_table(myIdx).day14, rep_table(myIdx).day15,
rep_table(myIdx).day16, rep_table(myIdx).day17, rep_table(myIdx).day18, rep_table(myIdx).day19, rep_table(myIdx).day20,
rep_table(myIdx).day21, rep_table(myIdx).day22, rep_table(myIdx).day23, rep_table(myIdx).day24, rep_table(myIdx).day25,
rep_table(myIdx).day26, rep_table(myIdx).day27, rep_table(myIdx).day28, rep_table(myIdx).day29, rep_table(myIdx).day30,
rep_table(myIdx).day31;
CLOSE myCUR1;
END REP_HELPER1;
I wish to do the part from open myCUR; to close myCUR; in a separate univesral procedure. As I have many functions like the above and the cursor is always different. So I would like to have one procedure which would do the open,fetch, close part :
PROCEDURE PB_HELPER_READ_INTO_DAYS(nIndex IN BINARY_INTEGER, myCUR by reference, rep_table IN OUT rep_table_T)
Is it possible to to it in plsql?
EDIT:
Based on yours clues I wrote it like this:
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
PROCEDURE REP_HELPER1 (myIdx IN BINARY_INTEGER, from_d IN DATE, rep_table IN OUT rep_table_T) IS
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
myCUR1 SYS_REFCURSOR;
BEGIN
OPEN myCUR1 FOR SELECT myField1,
myField2,
myField3,
myField4,
myField5,
myField6,
myField7,
myField8,
myField9,
myField10,
myField11,
myField12,
myField13,
myField14,
myField15,
myField16,
myField17,
myField18,
myField19,
myField20,
myField21,
myField22,
myField23,
myField24,
myField25,
myField26,
myField27,
myField28,
myField29,
myField30,
myField31
FROM myTable;
MY_READ(myIdx , myCUR1, rep_table)
END REP_HELPER1;
PROCEDURE MY_READ(myIdx IN BINARY_INTEGER, cur IN SYS_REFCURSOR, rep_table IN OUT rep_table_T) IS
BEGIN
FETCH cur INTO rep_table(myIdx).day1, rep_table(myIdx).day2, rep_table(myIdx).day3, rep_table(myIdx).day4, rep_table(myIdx).day5,
rep_table(myIdx).day6, rep_table(myIdx).day7, rep_table(myIdx).day8, rep_table(myIdx).day9, rep_table(myIdx).day10,
rep_table(myIdx).day11, rep_table(myIdx).day12, rep_table(myIdx).day13, rep_table(myIdx).day14, rep_table(myIdx).day15,
rep_table(myIdx).day16, rep_table(myIdx).day17, rep_table(myIdx).day18, rep_table(myIdx).day19, rep_table(myIdx).day20,
rep_table(myIdx).day21, rep_table(myIdx).day22, rep_table(myIdx).day23, rep_table(myIdx).day24, rep_table(myIdx).day25,
rep_table(myIdx).day26, rep_table(myIdx).day27, rep_table(myIdx).day28, rep_table(myIdx).day29, rep_table(myIdx).day30,
rep_table(myIdx).day31;
CLOSE cur;
END MY_READ;
Option which would work is to create a package, declare cursor globally and use it in any procedure you want. For example:
SQL> create or replace package pkg_test is
2 procedure p1;
3 end;
4 /
Package created.
SQL> create or replace package body pkg_test is
2 cursor c1 is select * from dept;
3 c1r c1%rowtype;
4
5
6 procedure p1 is
7 begin
8 open c1;
9 fetch c1 into c1r;
10 close c1;
11 end p1;
12 end;
13 /
Package body created.
SQL>
This won't work: declaring a cursor in one procedure and working with it in another:
SQL> create or replace package pkg_test is
2 procedure p1;
3 procedure p2;
4 end;
5 /
Package created.
SQL> create or replace package body pkg_test is
2 procedure p1 is
3 cursor c1 is select * from dept;
4 c1r c1%rowtype;
5 begin
6 null;
7 end p1;
8
9
10 procedure p2 is
11 begin
12 open c1;
13 fetch c1 into p1.c1r;
14 close c1;
15 end p2;
16 end;
17 /
Warning: Package Body created with compilation errors.
SQL> show err
Errors for PACKAGE BODY PKG_TEST:
LINE/COL ERROR
-------- -----------------------------------------------------------------
12/5 PL/SQL: SQL Statement ignored
12/11 PLS-00201: identifier 'C1' must be declared
13/5 PL/SQL: SQL Statement ignored
13/11 PLS-00201: identifier 'C1' must be declared
14/5 PL/SQL: SQL Statement ignored
14/11 PLS-00201: identifier 'C1' must be declared
SQL>
Also, you can't reference it using the "owner" procedure's prefix:
SQL> create or replace package body pkg_test is
2 procedure p1 is
3 cursor c1 is select * from dept;
4 c1r c1%rowtype;
5 begin
6 null;
7 end p1;
8
9
10 procedure p2 is
11 begin
12 open p1.c1;
13 fetch p1.c1 into p1.c1r;
14 close p1.c1;
15 end p2;
16 end;
17 /
Warning: Package Body created with compilation errors.
SQL> show err
Errors for PACKAGE BODY PKG_TEST:
LINE/COL ERROR
-------- -----------------------------------------------------------------
12/5 PL/SQL: SQL Statement ignored
12/14 PLS-00225: subprogram or cursor 'P1' reference is out of scope
13/5 PL/SQL: SQL Statement ignored
13/11 PLS-00225: subprogram or cursor 'P1' reference is out of scope
14/5 PL/SQL: SQL Statement ignored
14/11 PLS-00225: subprogram or cursor 'P1' reference is out of scope
SQL>
You can define the cursor in a package spec outside of any procedure or function. Then use that cursor virtually any where a cursor is valid (except as a reference cursor). Includes any procedure/function within the package or any standalone procedure/function, and even an anonymous block. Just be sure to reference as package_name.cursor_name anywhere outside of the package. See demo)
create or replace package pkg_test is
cursor c_dept is select * from dept;
procedure p1;
procedure p2;
end pkg_test;
/
This makes maintenance of the cursor quite easy since there is only one definition, so only one place of maintenance.
You can put only FETCH and CLOSE in a different procedure. Would be this (when you have only one OUT parameter, then I prefer a FUNCTION):
CREATE OR REPLACE FUNCTION REP_HELPER (myIdx IN BINARY_INTEGER, from_d IN DATE) RETURN SYS_REFCURSOR IS
myCur SYS_REFCURSOR;
BEGIN
OPEN myCur FOR
SELECT myField1, ...
FROM myTable;
RETURN myCur;
END REP_HELPER;
And use it like this:
DECLARE
cur SYS_REFCURSOR;
BEGIN
cur := REP_HELPER(...);
FETCH cur INTO ...
CLOSE cur;
END;
A more advanced solution would be dynamic SQL with DBMS_SQL Package:
CREATE OR REPLACE FUNCTION REP_HELPER(myIdx IN BINARY_INTEGER, from_d IN DATE) RETURN NUMBER IS
curid NUMBER := DBMS_SQL.OPEN_CURSOR;
sql_stmt VARCHAR2(32000);
BEGIN
sql_stmt := 'SELECT myField1, ... FROM myTable';
DBMS_SQL.PARSE(curid, sql_stmt, DBMS_SQL.NATIVE);
RETURN curid;
END REP_HELPER;
DECLARE
cur SYS_REFCURSOR;
curid NUMBER;
ret INTEGER;
BEGIN
curid := REP_HELPER(...);
ret := DBMS_SQL.EXECUTE(curid);
-- Switch from DBMS_SQL to native dynamic SQL
cur := DBMS_SQL.TO_REFCURSOR(curid);
FETCH cur INTO ...
CLOSE cur;
END;
or
CREATE OR REPLACE PROCEDURE REP_HELPER(curid IN OUT NUMBER, myIdx IN BINARY_INTEGER, from_d IN DATE) IS
sql_stmt VARCHAR2(32000);
BEGIN
sql_stmt := 'SELECT myField1, ... FROM myTable';
DBMS_SQL.PARSE(curid, sql_stmt, DBMS_SQL.NATIVE);
END REP_HELPER;
DECLARE
cur SYS_REFCURSOR;
curid NUMBER;
ret INTEGER;
BEGIN
curid NUMBER := DBMS_SQL.OPEN_CURSOR;
REP_HELPER(curid, ...);
ret := DBMS_SQL.EXECUTE(curid);
-- Switch from DBMS_SQL to native dynamic SQL
cur := DBMS_SQL.TO_REFCURSOR(curid);
FETCH cur INTO ...
CLOSE cur;
END;
But I think this would be an overkill.
Update:
You can compose the SQL string also dynamically, e.g.:
sql_stmt := 'SELECT ';
FOR i IN 1..31 LOOP
sql_stmt := sql_stmt || 'myField'||i||',';
END LOOP;
sql_stmt := REGEXP_REPLACE(sql_stmt, ',$');
sql_stmt := sql_stmt || ' FROM '||table_name;
sql_stmt := sql_stmt || ' WHERE the_date = :d';
OPEN cur FOR sql_stmt USING from_d;

How to solved error executing procedure in Oracle PL/SQL

Just started with the issue of procedures in PL/SQL Oracle and I am presenting a problem at the time of executing it, it indicates the error ORA-00984
The following is the code of the procedure I am performing
create or replace PROCEDURE P_FILEUPLOAD_XML IS
BEGIN
INSERT INTO SPRCMNT (
SPRCMNT_CMTT_CODE,
SPRCMNT_TEXT,
SPRCMNT_TEXT_NAR)
VALUES(P_CMTT_CODE,
P_TEXT,
P_TEXT_NAR);
EXCEPTION WHEN OTHERS THEN
COMMIT;
END;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('Error:' || SQLERRM);
DBMS_LOB.CLOSE(l_loc);
--dbms_output.put_line('P_RET_VAL:' || P_RET_VAL);
END;
This is the error when saving my procedure
PL/SQL: ORA-00984: column not allowed here
I do not know if I am missing any declaration of variables or something, as I say I am just beginning with the issue of procedures and request your help.
You can use this method to insert into your table. Where you assign the variables inside the procedure
create or replace PROCEDURE P_FILEUPLOAD_XML AS
-- Declare the Variables
P_CMTT_CODE VARCHAR2(200);
P_TEXT VARCHAR2(200);
P_TEXT_NAR VARCHAR2(200);
BEGIN
-- Set variables with a value
P_CMTT_CODE := 'VALUE 1';
P_TEXT := 'VALUE 2';
P_TEXT_NAR := 'VALUE 3';
-- Insert into table
INSERT INTO SPRCMNT
( SPRCMNT_CMTT_CODE,
SPRCMNT_TEXT,
SPRCMNT_TEXT_NAR )
VALUES
( P_CMTT_CODE,
P_TEXT,
P_TEXT_NAR );
EXCEPTION
-- Catch error and log result
WHEN OTHERS THEN
dbms_output.put_line('Error:' || SQLERRM);
END;
Or alternative pass the variables into the procedure. both will achieve the same result
create or replace PROCEDURE P_FILEUPLOAD_XML(P_CMTT_CODE VARCHAR2,P_TEXT VARCHAR2, P_TEXT_NAR VARCHAR2) AS
BEGIN
-- Insert into table
INSERT INTO SPRCMNT
( SPRCMNT_CMTT_CODE,
SPRCMNT_TEXT,
SPRCMNT_TEXT_NAR )
VALUES
( P_CMTT_CODE,
P_TEXT,
P_TEXT_NAR );
EXCEPTION
-- Catch error and log result
WHEN OTHERS THEN
dbms_output.put_line('Error:' || SQLERRM);
END;
-- How to run procedure
BEGIN
P_FILEUPLOAD_XML('VALUE1' , 'VALUE2', 'VALUE3');
END;

Error while creating PL/SQL procedure

I am trying to create the procedure below with PL/SQL, but it shows a red cross on the procedure name but no error was displayed so can anyone tell me what's wrong with that code
create or replace procedure CREATE_DM_CLIENT(
V_C_ID VARCHAR2,
V_S_ID VARCHAR2,
V_A_ID VARCHAR2,
V_J IN VARCHAR2,
V_H IN VARCHAR2,
V_COM IN VARCHAR2,
V_COD OUT VARCHAR2)
is
code_erreur number;
lib_erreur varchar(200) ;
num number := 0;
BEGIN
SELECT SEQ_DEM.NEXTVAL
INTO NUM
FROM DUAL;
INSERT INTO DM_CLIENTS(DM_C_ID, C_ID, S_ID, A, J, H, D_S, C)
VALUES(num, V_C_ID, V_S_ID, V_A_ID, V_J, V_H, SYSDATE, V_C);
--update num_client set etat=1 where num=V_CLIENT_ID;
commit;
V_COD:='100';
EXCEPTION
WHEN OTHERS THEN
l_e := SQLERRM ;
C_L := SQLCODE ;
insert into l_table (ligne , module)
values ( to_char(CODE_ERREUR)||LIB_ERREUR ,
'CREATE_DM_CLIENT' ) ;
commit;
V_CODEREP:='109';
end create_dm_client;
Compilation errors for PROCEDURE SAC.CREATE_DM_CLIENT
Error: PLS-00201: identifier 'L_E' must be declared
Line: 33
Text: l_e := SQLERRM;
Error: PL/SQL: Statement ignored
Line: 33
Text: l_e := SQLERRM;
Error: PLS-00201: identifier 'C_L' must be declared
Line: 34
Text: C_L := SQLCODE;
Error: PL/SQL: Statement ignored
Line: 34
Text: C_L := SQLCODE;
Error: PLS-00201: identifier 'V_CODEREP' must be declared
Line: 40
Text: V_CODEREP := '109';
Error: PL/SQL: Statement ignored
Line: 40
Text: V_CODEREP := '109';
other errors i did not mentioned, was because I don't have table name and sequences.
The 3 mentioned variables are not declared.
...
is
v_coderep varchar2(3);
c_l varchar2(3)
l_e varchar2(1024);
...
Please define l_e, C_L and V_CODEREP variables in variable declaration section. for example -
l_e varchar(20);
C_L integer;
V_CODEREP varchar(3);

calling stored procedure from anonymous block

I have problem reading result from plsql stored procedure written in sql developer on Oracle 11gr2 database on local machine.
This is my table:
create table MY_TEST_TABLE
(employee_id NUMBER(6)
,first_name VARCHAR2(20)
,last_name VARCHAR2(25)
,email VARCHAR2(25)
,phone_number VARCHAR2(20));
This is procedure declaration:
create or replace PACKAGE TEST_PACKAGE AS
procedure test_procedure (i_id in number,
o_data out sys_refcursor);
END TEST_PACKAGE;
This is body:
create or replace PACKAGE BODY TEST_PACKAGE AS
procedure test_procedure (i_id in number,
o_data out sys_refcursor) AS
BEGIN
open o_data for
select employee_id,
first_name,
last_name,
email,
phone_number
from my_test_table
where EMPLOYEE_ID = i_id;
close o_data;
END test_procedure;
END TEST_PACKAGE;
And this is anonymous block call:
SET serveroutput on
DECLARE
in_id number;
my_cursor sys_refcursor;
current_record my_test_table%ROWTYPE;
BEGIN
in_id := 1;
test_package.test_procedure(in_id, my_cursor);
open my_cursor;
LOOP
FETCH my_cursor INTO current_record;
EXIT WHEN my_cursor%NOTFOUND;
dbms_output.put_line(' - out - ' || current_record.employee_id);
END LOOP;
END;
I am getting error:
Error starting at line : 2 in command -
DECLARE
in_id number;
my_cursor sys_refcursor;
current_record my_test_table%ROWTYPE;
BEGIN
in_id := 1;
test_package.test_procedure(in_id, my_cursor);
open my_cursor;
LOOP
FETCH my_cursor INTO current_record;
EXIT WHEN my_cursor%NOTFOUND;
dbms_output.put_line(' - out - ' || current_record.employee_id);
END LOOP;
END;
Error report -
ORA-06550: line 8, column 5:
PLS-00382: expression is of wrong type
ORA-06550: line 8, column 5:
PL/SQL: SQL Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
Can someone explain what is wrong?
Tnx!
The cursor is opened in the procedure, so you don't need to, and can't, open it directly in your anonymous block. Well, it should be open, but you're also closing it in the procedure. Remove the close from the procedure, and the open from the block:
create or replace PACKAGE BODY TEST_PACKAGE AS
procedure test_procedure (i_id in number,
o_data out sys_refcursor) AS
BEGIN
open o_data for
select employee_id,
first_name,
last_name,
email,
phone_number
from my_test_table
where EMPLOYEE_ID = i_id;
-- close o_data;
END test_procedure;
END TEST_PACKAGE;
/
And:
DECLARE
in_id number;
my_cursor sys_refcursor;
current_record my_test_table%ROWTYPE;
BEGIN
in_id := 1;
test_package.test_procedure(in_id, my_cursor);
-- open my_cursor;
LOOP
FETCH my_cursor INTO current_record;
EXIT WHEN my_cursor%NOTFOUND;
dbms_output.put_line(' - out - ' || current_record.employee_id);
END LOOP;
END;
/
SQL Fiddle - just add data...

Resources