I am trying to lay the foundation for a package but am having trouble even getting started. I have successfully created a basic package spec and want to just test the package body but I'm having trouble getting it to compile. The spec code is:
CREATE OR REPLACE PACKAGE synchronize_my_data
AS
PROCEDURE synchronize_data(p_run_date IN date);
END synchronize_my_data;
and here is the package body code:
CREATE OR REPLACE PACKAGE BODY synchronize_my_data
IS
PROCEDURE synchronize_data(p_run_date IN date) IS
PROCEDURE process_deletes(p_run_date IN date) IS
BEGIN
dbms_output.put_line('Run Date: ' || to_char(p_run_date, 'MM/DD/YYYY'));
END process_deletes;
BEGIN
process_deletes(p_run_date);
END synchronize_data;
END synchronize_my_data;
I keep getting a compilation error but can't figure out what's wrong with the code. It seems like basic code, am I just missing something obvious?
That code seems to compile for me. What error are you getting?
SQL> CREATE OR REPLACE PACKAGE synchronize_my_data
2 AS
3 PROCEDURE synchronize_data(p_run_date IN date);
4 END synchronize_my_data;
5 /
Package created.
SQL> CREATE OR REPLACE PACKAGE BODY synchronize_my_data
2 IS
3 PROCEDURE synchronize_data(p_run_date IN date) IS
4 PROCEDURE process_deletes(p_run_date IN date) IS
5 BEGIN
6 dbms_output.put_line('Run Date: ' || to_char(p_run_date, 'MM/DD/YYYY'));
7 END process_deletes;
8 BEGIN
9 process_deletes(p_run_date);
10 END synchronize_data;
11
12 END synchronize_my_data;
13 /
Package body created.
From a general stylistic standpoint, it generally makes very little sense to define a procedure within another procedure in a package body. One of the benefits of using packages is that you can have both public and private procedures. You can create the process_deletes procedure as a private procedure simply by defining it in the body without defining it in the spec.
CREATE OR REPLACE PACKAGE BODY synchronize_my_data
IS
PROCEDURE process_deletes(p_run_date IN date)
IS
BEGIN
dbms_output.put_line('Run Date: ' || to_char(p_run_date, 'MM/DD/YYYY'));
END process_deletes;
PROCEDURE synchronize_data(p_run_date IN date)
IS
BEGIN
process_deletes(p_run_date);
END synchronize_data;
END synchronize_my_data;
That shouldn't have anything to do with whatever error you're getting. But it should make your code easier to deal with.
Related
CREATE OR REPLACE PACKAGE Learning_package AS
PROCEDURE add_person(name_person people.C_Name%type,
mail_person people.C_mail%type,
age_person people.C_age%TYPE);
END Learning_package;
CREATE OR REPLACE PACKAGE BODY Learning_package AS
PROCEDURE add_person(name_person people.C_Name%type,
mail_person people.C_mail%type,
age_person people.C_age%TYPE)
IS
BEGIN
INSERT INTO people (C_Name, C_mail, C_age)
VALUES (name_person, mail_person, age_person);
END add_person;
END Learning_package;
/
BEGIN
Learning_package.add_person('john', 'fffff#all.com', 20);
END;
an error appears:
package body "Learning_package" has erros PL/SQL: could not find
program unit being called "Learning_package" at line 3
Can someone help me?
Your code is fine except that you need to:
Make sure that you have a people table with the expected columns; and
Use a / statement terminator in a new line at the end of every PL/SQL statement.
Like this:
CREATE OR REPLACE PACKAGE Learning_package AS
PROCEDURE add_person(name_person people.C_Name%type,
mail_person people.C_mail%type,
age_person people.C_age%TYPE);
END Learning_package;
/
CREATE OR REPLACE PACKAGE BODY Learning_package AS
PROCEDURE add_person(name_person people.C_Name%type,
mail_person people.C_mail%type,
age_person people.C_age%TYPE)
IS
BEGIN
INSERT INTO people (C_Name, C_mail, C_age)
VALUES (name_person, mail_person, age_person);
END add_person;
END Learning_package;
/
BEGIN
Learning_package.add_person('john', 'fffff#all.com', 20);
END;
/
Note: Age is not a good thing to store as it quickly becomes out-of-date. Instead, you should store date-of-birth and when you need an age you can calculate it from the date-of-birth and today's date.
db<>fiddle here
Could you also add a block terminator after the package creation and change the AS to IS (/).
CREATE OR REPLACE PACKAGE Learning_package IS
END Learning_package;
/
Same goes for the package body.
When I am trying to execute this code I am getting the following error. I am not able to resolve this problem - what am I missing?
SHOW ERRORS;
Errors for PACKAGE BODY PKG_VIEW_LEDGER:
LINE/COL ERROR
-------- -----------------------------------------------------------------
0/0 PL/SQL: Compilation unit analysis terminated
1/14 PLS-00304: cannot compile body of 'PKG_VIEW_LEDGER' without its
specification
1/14 PLS-00905: object SYSTEM.PKG_VIEW_LEDGER is invalid
--- code below ---
CREATE OR REPLACE PACKAGE PKG_VIEW_LEDGER AS
TYPE cur_view_data is REF CURSOR;
PROCEDURE sp_view_ledger(person IN VARCHAR2, cur_inout IN OUT cur_view_data);
END PRG_VIEW_LEDGER;
/
CREATE OR REPLACE PACKAGE BODY PKG_VIEW_LEDGER AS
PROCEDURE sp_view_ledger( person IN VARCHAR2, cur_inout IN OUT cur_view_data)
IS
tmp_cursor cur_view_data;
BEGIN
OPEN tmp_cursor FOR
select * from ledger where person like '%" + myArg.ToUpper + "%';
cur_inout := tmp_cursor;
END sp_view_ledger;
END PKG_VIEW_LEDGER;
/
First, based on the error, you are creating the package in the SYSTEM schema. Don't do that. SYS and SYSTEM are special and should be used only by Oracle for objects delivered by Oracle. You'll need a new schema where you can create your own objects. SYS and SYSTEM are special and do not always behave the same way that normal schemas do so various bits of functionality will appear not to work correctly if you use these schemas.
Second, when you are defining the package specification, your END does not match your CREATE. You are creating PKG_VIEW_LEDGER while you are ending PRG_VIEW_LEDGER. PKG != PRG. If you had a show errors after creating the package specification, the error would tell you this.
I have modified the code and its working fine. Please try it from your side and let me know. Thanks.
CREATE OR REPLACE PACKAGE PKG_VIEW_LEDGER AS
TYPE cur_view_data is REF CURSOR;
PROCEDURE sp_view_ledger(person IN VARCHAR2, cur_inout IN OUT cur_view_data);
END PkG_VIEW_LEDGER;
--------------------------------------------------------------
Package created.
--------------------------------------------------------------
CREATE OR REPLACE PACKAGE PKG_VIEW_LEDGER AS
TYPE cur_view_data is REF CURSOR;
PROCEDURE sp_view_ledger(person IN VARCHAR2, cur_inout IN OUT cur_view_data);
END PRG_VIEW_LEDGER;
/
CREATE OR REPLACE PACKAGE BODY PKG_VIEW_LEDGER AS
PROCEDURE sp_view_ledger( person IN VARCHAR2, cur_inout IN OUT cur_view_data)
IS
tmp_cursor cur_view_data;
BEGIN
OPEN tmp_cursor FOR
select * from avrajit;
cur_inout := tmp_cursor;
END sp_view_ledger;
END PKG_VIEW_LEDGER;
/
-----------------------------------------------------
Package Body created.
0.04 seconds
I have a pkg that I use to keep report oriented code CMS_REPORTS.
I added a procedure to return a ref cursor and the pkg compiles fine, but fails when I call the proc to test it with:
ORA-04063: package body "CMS.CMS_REPORTS" has errors
ORA-06508: PL/SQL: could not find program unit being called: "CMS.CMS_REPORTS"
I've removed the orig proc and replaced it with this to keep things simple - same problem.
The proc is this:
procedure test_ref_cur(p_testno in number,
p_cur in out ref_cur) as
begin
open p_cur for
select p_testno + 1 from dual;
end test_ref_cur;
I have defined the ref cursor in the pkg spec like this:
type ref_cur is ref cursor;
procedure test_ref_cur(p_testno in number,
p_cur in out ref_cur);
I've tried all sorts of combinations of using ref cursor and sys_refcursor and all bring up the same error. If I remove the proc from the pkg, it works fine.
I'm beginning to think it's a system issue?
Has anyone else had this problem?
Regards
Dave
Hard to tell what is the issue here, since it doesn't look like we are seeing the relevant code.
So here are some thing I recommend to double check:
package and package body are there and are actually compiled without an exception
you are in the schema/user that contains package and package body.
There are no other objects with the same name, that might hide your package/package body
the procedure you try to call is present in package and package body.
remove all code from package + package body except a single trivial procedure and check if that works.
If you've done all that update the question with the results.
In order to achieve what you want you have to use SYS_REFCURSOR:
create procedure test_ref_cur(p_testno in number,
p_cur in out SYS_REFCURSOR) as
begin
open p_cur for
select p_testno + 1 from dual;
end test_ref_cur;
-- PROCEDURE TEST_REF_CUR compiled
... and example:
DECLARE
l_sysrc SYS_REFCURSOR;
l_num NUMBER;
procedure test_ref_cur(p_testno in number,
p_cur in out SYS_REFCURSOR) as
begin
open p_cur for
select p_testno + 1 from dual;
end test_ref_cur;
BEGIN
test_ref_cur(1, l_sysrc);
FETCH l_sysrc INTO l_num;
DBMS_OUTPUT.PUT_LINE(l_num);
END;
-- Result:
-- 2
Since Oracle 7.3 the REF CURSOR type has been available to allow
recordsets to be returned from stored procedures and functions. Oracle
9i introduced the predefined SYS_REFCURSOR type, meaning we no longer
have to define our own REF CURSOR types.
Source: http://www.oracle-base.com/articles/misc/using-ref-cursors-to-return-recordsets.php
How can I get a procedure/function name where an exception occurs in PLSQL?
I need this to create a log of the procedures that have problems in a package.
Unfortunately there is no way to get a stored procedure name, that is wrapped in a package, at run time. Any method, whether it $$PLSQL_UNIT inquiry directive or FORMAT_ERROR_BACKTRACE function of dbms_utility package, that allows you to do that in a case of a stand-alone stored procedure will always give you the anonymous block instead of a name in a case of a stored procedure that is wrapped in the package. Hence your only choice is to capture a package name and the line number on which an error has occurred by using dbms_utility.format_error_backtrace for example.
SQL> create or replace package some_pkg
2 as
3 procedure some_proc;
4 end;
5 /
Package created
SQL>
SQL> create or replace package body some_pkg
2 as
3 procedure Some_Proc
4 is
5 l_var number;
6 begin
7 l_var := 1/0;
8 exception
9 when others
10 then dbms_output.put_line(dbms_utility.format_error_backtrace);
11 end;
12 end;
13 /
Package body created
SQL> exec some_pkg.some_proc;
ORA-06512: at "HR.SOME_PKG", line 7
Did u mean get all procedures that has 'exception' in their source ?
if so then :
select distinct t.name from user_source t
where upper(t.text) like '%EXCEPTION%' or
upper(t.text) like '%RAISE_APPLICATION_ERROR%';
I hope it helps you :)
I have a package named save_db_values
I have two procedures named store_records and another one called db_activities.
db_activities will be called from my application by passing all values in db_activities I will be calling store_records procedure to do insert and delete.
Do I need to define store_records procedure in package specification? When I did not define store_records in specification I am getting error store_records not declared in this scope.
store_records procedure I do not want to expose and hence I did not add in specification.
How can I resolve this issue?
If you do not want some procedures to be publicly available you may not to declare them in the package specification. Declare them only in the package body. The cause of the error you are facing is declaration order of the procedures in the package body or lack of forward declaration. For example:
create or replace package Test_pkg as
2 procedure Proc1;
3 end;
4 /
Package created
create or replace package body Test_pkg as
2
3 procedure proc1 is
4 begin
5 proc2;
6 end;
7
8 procedure Proc2 is
9 begin
10 dbms_output.put_line('proc2 is being executed');
11 end;
12
13 end;
14 /
Warning: Package body created with compilation errors
Error: PLS-00313: 'PROC2' not declared in this scope
This is happening because we are calling Proc2 which declared later in the package. In this case our choices are:
Declare pro2 before the procedure which calls it
create or replace package body Test_pkg as
2
3
4 procedure Proc2 is
5 begin
6 dbms_output.put_line('proc2 is being executed');
7 end;
8
9 procedure proc1 is
10 begin
11 proc2;
12 end;
13
14 end;
15 /
Package body created
Use forward declaration.
create or replace package body Test_pkg as
2
3 procedure Proc2;
4
5 procedure proc1 is
6 begin
7 proc2;
8 end;
9
10 procedure Proc2 is
11 begin
12 dbms_output.put_line('proc2 is being executed');
13 end;
14
15
16 end;
17 /
Package body created
SQL> exec test_pkg.Proc1;
proc2 is being executed
PL/SQL procedure successfully completed
You can declare procedures just in the body, but the order in which they appear is relevant; the calling procedure must be defined after the called procedure. Or you use a forward declaration to make it easier:
package save_db_values is
procedure db_activities;
end save_db_values;
package body save_db_values is
procedure store records; -- forward declaration
procedure db_activities is
begin
store_records;
end;
procedure store records is
begin
null;
end;
end save_db_values;
It is happening because of writing procedure's body in the package body .
if you are not declaring any procedure in the package specification then you should write it at first place.
it will work :)