Oracle PL/SQL public variable with db link in package body - oracle

I'm trying to use a global variable in package body with db link but SQLDeveloper throws me PL:00352
CREATE OR REPLACE PACKAGE BODY my_package
AS
global_variable ANOTHER_TABLE#MY_DB_LINK.ANOTHER_FIELD%TYPE;
PROCEDURE my_procedure IS
variable1 my_table.my_field%TYPE;
BEGIN
do things;
END;
END my_package;
The global_variable line is throwing me PLS-00352: Unable to access another database 'MY_DB_LINK';
Maybe I am wrong with syntax?
Thanks in advance.

Wrong syntax.
Example: my database link works:
SQL> select * from dual#dbl_scott;
D
-
X
Declaring a variable that inherits datatype from emp table, empno column, over the database link:
SQL> declare
2 gl_var emp.empno#dbl_scott%type;
3 begin
4 null;
5 end;
6 /
PL/SQL procedure successfully completed.
SQL>
So, it is: table.column#database_link%type
In your case:
global_variable another_table.another_field#my_db_link%type;

Related

How to call stored procedure with only OUT parameter?

I have created a stored procedure in Oracle 11g:
CREATE OR REPLACE PROCEDURE greetings(cnt OUT VARCHAR2)
AS
BEGIN
SELECT COUNT(*)
INTO cnt
FROM SYS.all_tables;
END greetings;
but I am unable to call it.
I have tried the following code snippets:
EXEC GREETINGS();
EXEC GREETINGS;
CALL GREETINGS;
The procedure requires one parameter, so - provide it.
SQL> CREATE OR REPLACE PROCEDURE greetings(cnt OUT VARCHAR2)
2 AS
3 BEGIN
4 SELECT COUNT(*)
5 INTO cnt
6 FROM SYS.all_tables;
7 END greetings;
8 /
Procedure created.
One option, which works everywhere, is to use an anonymous PL/SQL block:
SQL> set serveroutput on
SQL> declare
2 l_cnt number;
3 begin
4 greetings(l_cnt);
5 dbms_output.put_line(l_cnt);
6 end;
7 /
87
PL/SQL procedure successfully completed.
Another one works in SQL*Plus (or any other tool which is capable of simulating it):
SQL> var l_cnt number;
SQL> exec greetings(:l_cnt);
PL/SQL procedure successfully completed.
SQL> print l_cnt;
L_CNT
----------
87
Regarding the call example, this is explained in EXECUTE recognizes a stored procedure, CALL does not. It's not obvious from the syntax documentation but it does require brackets, so it is (rather unhelpfully) rejecting the whole thing and giving the impression that greetings is the problem, when actually it is not:
SQL> call greetings;
call greetings
*
ERROR at line 1:
ORA-06576: not a valid function or procedure name
while using the mandatory brackets gets you the real issue:
SQL> call greetings();
call greetings()
*
ERROR at line 1:
ORA-06553: PLS-306: wrong number or types of arguments in call to 'GREETINGS'
As others have pointed out, you are missing the parameter.
SQL> var n number
SQL>
SQL> call greetings(:n);
Call completed.
SQL> print :n
N
----------
134
execute is just a handy SQL*Plus shortcut for the PL/SQL block begin xxx; end; which is less fussy about brackets and gives the same error message with or without them.
(variable and print are SQL*Plus commands and may not be supported in other environments.)
There's no problem with the procedure body. You can call like this :
SQL> var nmr number;
SQL> exec greetings(:nmr);
PL/SQL procedure successfully completed
nmr
------------------------------------------
306 -- > <a numeric value returns in string format>
Oracle doesn't care assigning a numeric value to a string. The execution prints the result directly, but whenever you want you can recall that value of variable(nmr) again, and print as
SQL> print nmr
nmr
---------
306

Oracle PL/SQL Developer: Return %RowType from Package Procedure

i'm kind of new to Oracle Pl\SQL. I was just trying to create a simple Package with a procedure that returns a set of object id's; the code is as follows:
--Package Spec
CREATE OR REPLACE PACKAGE TEST IS
--GET OBJECT ID'S FROM CONTROL TABLE
PROCEDURE get_object_id_control(p_obj_id OUT abc_table%ROWTYPE);
END;
--Package Body
PROCEDURE get_object_id_control(p_obj_id OUT abc_table%ROWTYPE) AS
BEGIN
SELECT object_id
INTO p_obj_id
FROM abc_table
WHERE fec_proc IS NULL;
END;
I get Error: PL/SQL: ORA-00913: too many values. Is this the correct way for returning multiple values of same data type, or is there a better approach. Thanks in advance.
You can create a custom table type and set the out parameter of the procedure to that type.
CREATE TABLE ABC_TABLE(ID varchar2(100));
create or replace type abc_tab is table of varchar2(100);
/
CREATE OR REPLACE PACKAGE TEST IS
PROCEDURE get_object_id_control(p_obj_id OUT abc_tab);
END;
/
CREATE OR REPLACE PACKAGE BODY TEST IS
PROCEDURE get_object_id_control(p_obj_id OUT abc_tab) AS
BEGIN
SELECT id
bulk collect INTO p_obj_id
FROM abc_table;
END;
END;
/
Then you can call it like so:
declare
v abc_tab;
begin
TEST.get_object_id_control(p_obj_id => v);
for i in v.first..v.last loop
dbms_output.put_line(v(i));
end loop;
end;
/
Similar to GurV's answer (since he beat me by like 30 seconds...), you can use a PL/SQL object type as well. You do not need the CREATE TYPE statement if you don't need to reference the type in SQL.
--Package Spec
CREATE OR REPLACE PACKAGE TEST AS
TYPE id_table_type IS TABLE OF NUMBER;
--GET OBJECT ID'S FROM CONTROL TABLE
PROCEDURE get_object_id_control(p_obj_id_list OUT id_table_type);
END;
--Package Body
CREATE OR REPLACE PACKAGE BODY TEST AS
PROCEDURE get_object_id_control(p_obj_id_list OUT id_table_type) AS
BEGIN
SELECT object_id
BULK COLLECT INTO p_obj_id_list
FROM abc_table
WHERE fec_proc IS NULL;
END;
END;
To use it:
DECLARE
l_id_list test.id_table_type;
BEGIN
test.get_object_id_control (p_obj_id_list => l_id_list);
FOR i IN l_id_list.FIRST .. l_id_list.LAST LOOP
DBMS_OUTPUT.put_line (l_id_list (i));
END LOOP;
END;

Package in Oracle (facing error while calling it)

I am using Oracle 11G database. I have created a package as described below:
create or replace package forward_emp is
Function emp_sal_avg return number;
Procedure emp_new_sal;
End forward_emp;
/
package created.
Then I created the package body:
create or replace package body forward_emp is
Function emp_sal_avg return number is
avg_sal emp.salary%type;
Begin
Select avg (salary) into avg_sal
from emp;
Return avg_sal;
End emp_sal_avg;
Procedure emp_new_sal is
Begin
Insert into Emp (salary) values (emp_sal_avg);
End emp_new_sal;
End forward_emp;
/
Package body created.
Now when I tried calling the package its is showing error.
Call forward_emp.emp_new_sal;
ORA- 06576: not a valid function or procedure.
Please help. Not been able to understand the problem.
CALL is a SQL statement, not a PL/SQL statement, not a SQLPLUS command. CALL can be used in SQLPLUS directly, but, when you execute a function, the returning result should be stored somewhere, hence into clause of the call statement is needed. And parenthesis, even if a function or a stored procedure has no arguments, kind of mandatory.
Here is an example:
SQL> create or replace package pkg as
2 function f1 return number;
3 procedure p1;
4 end;
5 /
Package created.
SQL> create or replace package body pkg as
2 function f1 return number is
3 begin
4 return 12345;
5 end;
6 procedure p1 is
7 begin
8 null; -- does nothing
9 end;
10 end;
11 /
Package body created.
Now let's execute those procedure and function defined withing the PKG package:
-- variable, which is going to store result the function returns
SQL> variable f_res number;
-- executing the F1 function
SQL> call pkg.f1() into :f_res;
Call completed.
-- print the result
SQL> print f_res;
F_RES
----------
12345
-- executing the P1 procedure
SQL> call pkg.p1();
Call completed.
This what happens if we simply omit parenthesis or do not specify into clause when executing a stored procedure or a type method using CALL statement:
SQL> call pkg.p1;
call pkg.p1
*
ERROR at line 1:
ORA-06576: not a valid function or procedure name
SQL> call pkg.f1 into :f_res;
call pkg.f1 into :f_res
*
ERROR at line 1:
ORA-06576: not a valid function or procedure name
SQL> call pkg.f1();
call pkg.f1()
*
ERROR at line 1:
ORA-06576: not a valid function or procedure name
I think you're trying to use CALL as a SQL*Plus command. As AHWNN pointed out, in sqlplus you would use EXECUTE to run the procedure. However you could in SQL test with CALL by using an anonymous block:
BEGIN
CALL the_pack.the_proc;
END;
/

How can I get the procedure/function name where an exception occurs, in PLSQL?

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 :)

Some mistake in calling one procedure from another

Due to a requirement I have to call one stored procedure from another.
The problem seems to be somewhere around the output parameter out_result_size, which I am using. When I test main_func it works fine but when I test synonym_proc it says
synonym_proc is invalid
I have to, ultimately, call synonym_proc from Java using JPA's #NamedNativeQuery
CREATE OR REPLACE PROCEDURE synonym_proc (
result_cursor OUT SYS_REFCURSOR,
in_cp_id IN NUMBER,
in_cp_name IN VARCHAR2 := NULL,
in_country_name IN VARCHAR2 := NULL,
in_industry_name IN VARCHAR2 := NULL,
in_max_result_size IN NUMBER
) AS
out_result_size NUMBER;
BEGIN
result_cursor := someSchema.somePackage.main_func(in_cp_id,
in_cp_name,
in_country_name,
in_industry_name,
in_max_result_size,
out_result_size);
END;
UPDATE: Apologies for not mentioning the changes in the question which I didn't notice earlier. The main_func is a function (not procedure), which returns a cursor and resides inside some package which is in some schema. When I compile I get the following compilation errors:
Error: PLS-00201: identifier 'SOMESCHEMA.SOMEPACKAGE' must be
declared.. statement ignored.
Update 2
SomeSchema definition
CREATE OR REPLACE PACKAGE someSchema."SomePackage"
is
...
function mainFunc
(
in_cp_id in gem.tcp_real_profile_main_approved.cp%type
, in_cp_name in gem.tcp_real_profile_main_approved.name%type
, in_country_name in gem.tcp_real_profile_main_approved.country_name%type
, in_industry_name in gem.tcp_real_profile_main_approved.industry_name%type
, in_max_result_size in number
, out_result_size out number
)
return search_result_type_cursor;
ADDED
type search_result_type_cursor
is ref cursor
return search_type;
And yes the datatypes are correct since I described the function (main_func) and cross verified the datatypes.
Based on the comments, particularly that you can describe and test the procedure in the other schema, it looks like this may be a permission issue. If your privileges on the objects in the other schema are granted via a role then you will be able to execute the package procedure directly, but roles aren't recognised inside named blocks. If this is the issue then you will have to get execute permission on someSchema.somePackage granted directly to the user that is creating the stored procedure.
To demonstrate the issue, I can create a package in my SCOTT schema and grant execute on it to a role, and grant that role to a user - both of which I've created for the test. As SYS:
create role scott_tmp_role;
grant connect to someuser identified by <password>;
grant scott_tmp_role to someuser;
grant create procedure to someuser;
As SCOTT:
create package p42 as
procedure proc;
end p42;
/
Package created.
create package body p42 as
procedure proc is
begin
null;
end proc;
end p42;
/
Package body created.
grant execute on p42 to scott_tmp_role;
Grant succeeded.
As my new SOMEUSER, verify the roles I have:
select * from session_roles;
ROLE
------------------------------
CONNECT
SCOTT_TMP_ROLE
I can execute the procedure in an anonymous block:
begin
scott.p42.proc;
end;
/
PL/SQL procedure successfully completed.
... but not in a named block:
create or replace procedure sp42 as
begin
scott.p42.proc;
end;
/
Warning: Procedure created with compilation errors.
show errors
Errors for PROCEDURE SP42:
LINE/COL ERROR
-------- -----------------------------------------------------------------
3/2 PL/SQL: Statement ignored
3/2 PLS-00201: identifier 'SCOTT.P42' must be declared
If SCOTT grants the permission directly to my new user:
grant execute on p42 to someuser;
... then the named block now works:
create or replace procedure sp42 as
begin
scott.p42.proc;
end;
/
Procedure created.
If you want to see where you might be getting the execute permission from, you can run a query like this, although there may be a hierarchy of roles to pick through:
select grantee, privilege from all_tab_privs
where table_schema = 'SomeSchema'
and table_name = 'SomePackage';
You can't specify the size of parameters for a procedure or function. Try removing the sizes, as well as moving the commit as Vincent suggested.
CREATE OR REPLACE PROCEDURE synonym_proc(result_cursor OUT SYS_REFCURSOR,
in_cp_id IN NUMBER,
in_cp_name IN VARCHAR2,
in_country_name IN VARCHAR2,
in_industry_name IN VARCHAR2,
in_max_result_size IN NUMBER) AS
out_result_size NUMBER;
BEGIN
main_proc(result_cursor,
in_cp_id,
in_cp_name,
in_country_name,
in_industry_name,
in_max_result_size,
out_result_size);
COMMIT;
END;
You should be getting an error like PLS-00103: Encountered the symbol "(" when expecting one of the following: ...
Syntax for Oracle SP is
CREATE OR REPLACE PROCEDURE procedure_name(--parameter list) AS
--Local Variables
BEGIN
--Body
END;
Now you have made a mistake that instead of putting COMMIT before END you have placed it after END. It should be like this
COMMIT;
END;

Resources