This is my first attempt at creating a package, so I must be missing something really really obvious (nothing that I've Googled for seems to even consider it worth mentioning).
Obviously, if you have procedures in your package body that are not included in the specification section, then those procedures are private. The problem I've got is that I can't seem to figure out how to reference those private packages once I've made them. And SQL Developer refuses to give me any message more useful than 'execution completed with warning', which doesn't help...
As an example, this is what I've been trying that doesn't work (just throws the aforementioned compiler error):
CREATE OR REPLACE PACKAGE BODY testPackage AS
PROCEDURE privateProc; --Forward declaration
PROCEDURE publicProc IS
BEGIN
EXECUTE privateProc();
END;
PROCEDURE privateProc IS
BEGIN
DBMS_OUTPUT.PUT_LINE('test');
END;
END testPackage;
I've also tried referring to it as testPackage.privateProc, which hasn't worked either.
What am I doing wrong?
I think you should do this:
CREATE OR REPLACE PACKAGE BODY testPackage AS
PROCEDURE privateProc; --Forward declaration
PROCEDURE publicProc IS
BEGIN
privateProc();
END;
PROCEDURE privateProc IS
BEGIN
DBMS_OUTPUT.PUT_LINE('test');
END;
END testPackage;
Just call privateProc as if it is part of the language. Execute is for running DML or SQL inside your PL/SQL.
CREATE OR REPLACE PACKAGE BODY testPackage AS
PROCEDURE publicProc; --Forward declaration
PROCEDURE publicProc IS
BEGIN
privateProc; --exec privateProc;
END;
PROCEDURE privateProc IS
BEGIN
DBMS_OUTPUT.PUT_LINE('test');
END;
END testPackage;
//call testPackage.publicProc
Related
My package header code looks like this:
CREATE OR REPLACE PACKAGE INST_PKG IS
...
FUNCTION Check_View (
view_name_ IN VARCHAR2 ) RETURN BOOLEAN;
PRAGMA restrict_references (Check_View, WNDS);
...
END INST_PKG;
And the body of the function is defined as follows:
CREATE OR REPLACE PACKAGE BODY INST_PKG IS
....
FUNCTION View_Exist (
view_name_ IN VARCHAR2 ) RETURN BOOLEAN
IS
ck_ NUMBER := 0;
CURSOR check_view IS
SELECT 1
FROM user_views uv
WHERE uv.view_name = upper(view_name_);
BEGIN
OPEN check_view;
FETCH check_view INTO ck_;
IF check_view%FOUND THEN
CLOSE check_view;
RETURN true;
ELSE
CLOSE check_view;
RETURN false;
END IF;
END View_Exist;
....
END INST_PKG;
I get an error message which reads as follows, when I try to compile the package body:
Compilation errors for PACKAGE BODY INST_PKG
Error: PLS-00452: Subprogram 'VIEW_EXIST' violates its associated pragma
Line: 684
Text: FUNCTION View_Exist (
Clearly, my pragma of "Write No Database State" is not violated, as there are no DML statements in the function. Has anyone seen such behaviour before?
Of course, I could drop the Pragma reference, but that would kind of defeat the purpose.
Worthy of note:
My database has been exported from an Oracle 10g instance, and has been re-imported to 12c. (This is an upgrade test, as you might imagine). Hence I get the above error on Oracle 12c.
I have tried to drop and re-create the package, but that doesn't seem to change things.
I have a feeling that there may be a library reference somewhere that has been imported in error, because when I drop the package, the same error comes up in another package, which contains a function of the same name. But when I re-create the INST_PKG, the second package compiles fine, almost as though the problem in the first package is masking it from being flagged in the second.
It emerges from the link you showed, that the issue is a result of a bug in USER_VIEWS (Oracle forgot to associate PRAGMA restrict_references with NO_ROOT_SW_FOR_LOCAL).
In this case you can be certain that your function doesn't violate WNDS assertion (doesn't write to the database), therefore just use TRUST option to disable assertions validation during compilation:
PRAGMA restrict_references (Check_View, WNDS, TRUST);
Thanks for pointing me in the right direction #MuhammadMuzzam. The problem is user_views has some references which apparently violate Pragma in Oracle 12.
Seems to be an known issue:
https://community.oracle.com/thread/3650610?start=0&tstart=0
I am running a method (the method name is sent by the end user) using dynamic PL/SQL (ex: EXECUTE IMMEDIATE).
When the method signature does not match the error ORA-06550 is raised (PLS-00306 is also mentioned in the stack).
I need to raise a custom message when the method signatures does not match with the required signature.
So I catch ORA-06550 inside the PL/SQL exception block and raise an error. Only to notice that ORA-06550 is raised for any invalid PL/SQL code (including method signature mismatch)
My Questions
What is the difference between ORA- type messages and PLS- types ones. Can't one catch PLS- type messages (ex: PLS-00306) like they do catch ORA- type ones (ex: ORA-06550). If possible how?
If not possible how to catch signature mismatches? (apart from running a query against USER_ARGUMENTS)
PLS-errors are PL/SQL compiler's compilation errors and can't be directly caught run-time as they are wrapped with ORA-errors.
If the compilation error is triggered by static PL/SQL the unit under compilation is created as invalid and execution of the unit triggers PLS-00905 (wrapped with ORA-06550).
If the compilation error is triggered by dynamic PL/SQL the unit under compilation is created without errors as dynamic PL/SQL is not checked during compilation. Instead the error is raised run-time when the unit is executed and can be caught but only ORA-code, not PLS-code. If you have do something based on PLS-code process the error stack string:
create or replace function get_custom_error(p_pls_code in varchar2) return varchar2 is
begin
return
case p_pls_code
when 'PLS-00201' then 'this is my custom error code'
else 'unknown PLS error code'
end;
end;
/
show errors
create or replace procedure foo is
plsql_compilation_error exception;
pragma exception_init(plsql_compilation_error, -6550);
v_a number;
begin
dbms_output.put_line('foo started');
execute immediate 'begin bar; end;';
dbms_output.put_line('foo ended normally');
exception
when plsql_compilation_error then
declare
v_pls_error_code constant varchar2(20) :=
regexp_substr(dbms_utility.format_error_stack,
'(PLS-[[:digit:]]+):', 1, 1, '', 1);
begin
dbms_output.put_line(get_custom_error(v_pls_error_code));
end;
end;
/
show errors
Execution example:
SQL> exec foo
foo started
this is my custom error code
PL/SQL procedure successfully completed.
SQL>
All Oracle error codes are listed and explained in Oracle Database Error Messages.
1) The difference between ORA and PLS is which engine raised the exception. Error on the top of error stack shows general error. Deeper errors provides more and more details. Like ORA-06550 happened because of PLS-00306
2) In any potentially dangerous place you should add BEGIN…EXCEPTION…END. To differentiate any ORA error you can declare exception in parent block and use PRAGMA directive to link it with error code.
begin
…
begin
…
execute immediate …
exception
when …
end;
…
end;
Oracle package is combination of two parts : The Specification and the Body
in oracle
Can we create a package Specification without body ?
Can we create a package body without specification ?
Can we create a package Specification without body ?
Yes, and these are quite useful when the package only contains variable and/or type declarations, e.g.
CREATE PACKAGE no_body AS
gc_yes CONSTANT VARCHAR2(1) := 'Y';
END;
Can we create a package body without specification ?
Yes, you can, but it's not very useful as it will be invalid and cannot be used, e.g.:
CREATE PACKAGE BODY no_spec AS
PROCEDURE myproc AS BEGIN null; END;
END no_spec;
/
The package body won't be usable until you compile a package specification for it.
The answer is quite simple:
Specification - yes. Body - no (it will be created but will be invalid).
I am using oracle 10g and toad 11.5. I am trying to call an api from an anonymous block.
If I recompile the api after adding dbms_output.put_line and then try to execute the anonymous block, it shows error as:
"ORA-06508: PL/SQL: could not find program unit being called".
However if I end current session and open a new session, then the anonymous block will execute with out the error.
Due to this issue, i am made to reconnect the session everytime i make a change to API.
Can anyone help if this issue can be resolved by making any configurations in toad or database level.
I suspect you're only reporting the last error in a stack like this:
ORA-04068: existing state of packages has been discarded
ORA-04061: existing state of package body "schema.package" has been invalidated
ORA-04065: not executed, altered or dropped package body "schema.package"
ORA-06508: PL/SQL: could not find program unit being called: "schema.package"
If so, that's because your package is stateful:
The values of the variables, constants, and cursors that a package
declares (in either its specification or body) comprise its package
state. If a PL/SQL package declares at least one variable, constant,
or cursor, then the package is stateful; otherwise, it is stateless.
When you recompile the state is lost:
If the body of an instantiated, stateful package is recompiled (either
explicitly, with the "ALTER PACKAGE Statement", or implicitly), the
next invocation of a subprogram in the package causes Oracle Database
to discard the existing package state and raise the exception
ORA-04068.
After PL/SQL raises the exception, a reference to the package causes
Oracle Database to re-instantiate the package, which re-initializes
it...
You can't avoid this if your package has state. I think it's fairly rare to really need a package to be stateful though, so you should revisit anything you have declared in the package, but outside a function or procedure, to see if it's really needed at that level. Since you're on 10g though, that includes constants, not just variables and cursors.
But the last paragraph from the quoted documentation means that the next time you reference the package in the same session, you won't get the error and it will work as normal (until you recompile again).
seems like opening a new session is the key.
see this answer.
and here is an awesome explanation about this error
Based on previous answers. I resolved my issue by removing global variable at package level to procedure, since there was no impact in my case.
Original script was
create or replace PACKAGE BODY APPLICATION_VALIDATION AS
V_ERROR_NAME varchar2(200) := '';
PROCEDURE APP_ERROR_X47_VALIDATION ( PROCESS_ID IN VARCHAR2 ) AS BEGIN
------ rules for validation... END APP_ERROR_X47_VALIDATION ;
/* Some more code
*/
END APPLICATION_VALIDATION; /
Rewritten the same without global variable V_ERROR_NAME and moved to procedure under package level as
Modified Code
create or replace PACKAGE BODY APPLICATION_VALIDATION AS
PROCEDURE APP_ERROR_X47_VALIDATION ( PROCESS_ID IN VARCHAR2 ) AS
**V_ERROR_NAME varchar2(200) := '';**
BEGIN
------ rules for validation... END APP_ERROR_X47_VALIDATION ;
/* Some more code
*/
END APPLICATION_VALIDATION; /
I recompiled the package specification, even though the change was only in the package body. This resolved my issue
I am completely new to Oracle.
I am trying to create a package but it throws me an error:
Source does not have a runnable target.
What i want to do is create a package and define some stored procs in the package body.
This is how my package definition looks like:
CREATE OR REPLACE
PACKAGE PAY_ZONE_PKG AS
TYPE CURSOR_TYPE IS REF CURSOR;
PROCEDURE spGetZones(Zones_Cursor OUT CURSOR_TYPE);
END PAY_ZONE_PKG;
This is how my package body looks like:
create or replace
PACKAGE BODY PAY_ZONE_PKG IS
PROCEDURE spGetZones(Zones_Cursor OUT CURSOR_TYPE) AS
BEGIN
OPEN Zones_Cursor FOR
SELECT *
FROM ESP.PAY_ZONE
ORDER BY NAME ASC;
EXCEPTION
WHEN NO_DATA_FOUND
THEN NULL;
END spGetZones;
END PAY_ZONE_PKG;
When i tried to create package body, it throws the error saying
cannot compile body of 'PAY_ZONE_PKG' without its specification
What am i missing here?
cannot compile body of 'PAY_ZONE_PKG' without its specification indicates that the create or replace package PAY_ZONE_PKG was either unsucessful, or that the package specification was deleted after it was tried to compile the body.
So, the problem is not with the body, but with the specification.
I'm not able to reproduce that.
The code:
CREATE OR REPLACE
PACKAGE PAY_ZONE_PKG AS
TYPE CURSOR_TYPE IS REF CURSOR;
PROCEDURE spGetZones(Zones_Cursor OUT CURSOR_TYPE);
END PAY_ZONE_PKG;
compiles.
And also the body is created successfully.
Have you tried to create them independently. First spec, and after, body.