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;
Related
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;
I am trying to implement database security as exposed in Oracle Database Security Guide and my scenario is like this:
user OWNER create table TABLE_A;
user OWNER create a package PKG_A wrapping business logic on TABLE_A like this:
package body PKG_A AS
procedure doSomeManagerStuff (pRow TABLE_A%rowtype) as
begin
...
end;
procedure doSomeDataEntryStuff (pRow TABLE_A%rowtype) as
begin
...
end;
procedure doSomeVisitorStuff (pRow TABLE_A%rowtype) as
begin
...
end;
end PKG_A;
-user OWNER create n procedures each calling a single public procedure of the package :
procedure ManagerStuff (pRow TABLE_A%rowtype) as
begin
pkg_a.doSomeManagerStuff (pRow);
end;
procedure DataEntryStuff (pRow TABLE_A%rowtype) as
begin
pkg_a.doSomeDataEntryStuff (pRow);
end;
procedure VisitorStuff(pRow TABLE_A%rowtype) as
begin
pkg_a.doSomeVisitorStuff (pRow);
end;
user OWNER create roles ROLE_MANAGER, ROLE_DATAENTRY, ROLE_VISITOR
user OWNER grant ONLY execute on procedure for the corresponding role
at this point in order to test the security I create different user with different role and try a script like this :
/** CONNECTED AS USERMANAGER **/
declare
lRow OWNER.TABLE_A%rowtype; /* --- Which privilege I need to grant? --- */
begin
lRow.field1 := value;
...
OWNER.ManagerStuff(lRow);
end;
I would like to work with procedures passing a single parameter that represent the whole table row. In this way my will is to have not to modify every procedure everytime I change the table structure or the business logic applied in the package.
Any suggestion or different approach will be appreciated.
I use an answer to better expose a solution.
The comment of William Robertson is correct but I read here about the SELECT privilege. So I do not want users can directly access my tables and with the READ privilege I can reference the rowtype in this way:
declare
lRow owner.table_a%rowtype;
begin
null;
end;
I read this and although the post is old I try this :
I create a package without body like this:
create or replace PACKAGE PKG_TYPES AS
subtype table_A_rt is table_A%rowtype;
subtype table_B_rt is table_B%rowtype;
subtype table_C_rt is table_C%rowtype;
...
END PKG_TYPES
grant EXECUTE on pkg_types to ROLE_MANAGER
the rowtype can be now referenced :
declare
lRow asadmin.pkg_types.account_rt;
begin
null;
end;
I am still working on it but it seems to meet my needs.
Any pros and cons are appreciated.
I'm trying to write an Oracle PL/SQL function similar to
create or replace function fn1(p_id in number) return number is
crec otheruser.thetable%rowtype;
begin
...
end;
but I get an error saying "Identifier 'OTHERUSER.THEABLE' must be declared". This same construct works fine if I login as otheruser. I'm able to select * from otheruser.thetable so it seems to me that my account can see the table just fine. I'm thinking it's a grant issue but I don't know what it could be.
You need to either use:
GRANT SELECT ON OtherUser.TheTable TO ThisUser;
Then you can use ROWTYPE directly in ThisUser session:
DECLARE
a_row OtherUser.TheTable%ROWTYPE;
BEGIN
NULL;
END;
/
But the ThisUser will also be able to select all the data from OtherUser.TheTable.
Or, if you do not want to grant the SELECT privilege you can create a package and grant on that:
CREATE PACKAGE OtherUser.TheTable_Pkg
AS
SUBTYPE TheTable_RowType IS OtherUser.TheTable%ROWTYPE;
END;
/
GRANT EXECUTE ON OtherUser.TheTable_Pkg TO ThisUser;
Then you can do, as ThisUser:
DECLARE
a_row OtherUser.TheTable_Pkg.TheTable_RowType;
BEGIN
NULL;
END;
/
And the type can be used but the data in the table is still inaccessible.
I have a routine whose task is to extract code from ALL_SOURCE. This is done using the following cursor:
CURSOR w_cur ( p_name VARCHAR2 , p_type VARCHAR2) IS
SELECT text , line
FROM ALL_SOURCE
WHERE UPPER(TYPE) = UPPER(p_type)
AND UPPER(NAME) = UPPER(p_name)
AND UPPER(OWNER) = UPPER(NVL(G_Owner_to_User,USER))
ORDER BY line
;
I'm executing this routine from a user with DBA and SYS privileges.
When attempting to extract the "BODY" of a "PACKAGE", if the package belongs to the same user running the program, I get the correct result. If, on the other hand, I attempt to extract the "BODY" of a package that belongs to another user, I get an empty result.
The interesting thing is that, when running the above "SELECT" from within SQL DEVELOPER (same user) I do get the expected code.
This looks like a "PRIVILEGE" related thing, but I have no idea why I'm getting different results and which privilege is missing.
Thanks for your comments.
Fernando.
Create the procedure with AUTHID CURRENT_USER and Oracle will use the invoker's roles to determine access privileges. The default is AUTHID DEFINER, which does not include privileges granted through a role (except for special roles like PUBLIC).
These functions show the difference between invoker's and definer's rights with ALL_SOURCE.
create or replace function count_source_invoker return number authid current_user is
v_count number;
begin
select count(*) into v_count from all_source;
return v_count;
end;
/
create or replace function count_source_definer return number authid definer is
v_count number;
begin
select count(*) into v_count from all_source;
return v_count;
end;
/
select
(select count(*) from all_source) real_count,
count_source_invoker,
count_source_definer
from dual;
Results:
REAL_COUNT COUNT_SOURCE_INVOKER COUNT_SOURCE_DEFINER
---------- -------------------- --------------------
333677 333677 142871
I executed a PL/SQL script that created the following table
TABLE_NAME VARCHAR2(30) := 'B2BOWNER.SSC_Page_Map';
I made an insert function for this table using arguments
CREATE OR REPLACE FUNCTION F_SSC_Page_Map_Insert(
p_page_id IN B2BOWNER.SSC_Page_Map.Page_ID_NBR%TYPE,
p_page_type IN B2BOWNER.SSC_Page_Map.Page_Type%TYPE,
p_page_dcpn IN B2BOWNER.SSC_Page_Map.Page_Dcpn%TYPE)
I was notified I had to declare B2BOWNER.SSC_Page_Map prior to it appearing as an argument to my function. Why am I getting this error?
EDIT: Actual error
Warning: compiled but with compilation errors
Errors for FUNCTION F_SSC_PAGE_MAP_INSERT
LINE/COL ERROR
-------- -----------------------------------------------------------------
2/48 PLS-00201: identifier 'SSC_PAGE_MAP.PAGE_ID_NBR' must be declared
0/0 PL/SQL: Compilation unit analysis terminated
EDIT: Complete PL/SQL Function
RETURN INTEGER
IS
TABLE_DOES_NOT_EXIST exception;
PRAGMA EXCEPTION_INIT(TABLE_DOES_NOT_EXIST, -942); -- ORA-00942
BEGIN
INSERT INTO
B2BOWNER.SSC_Page_Map VALUES(
p_page_id,
p_page_type,
p_page_dcpn);
RETURN 0;
EXCEPTION
WHEN TABLE_DOES_NOT_EXIST THEN
RETURN -1;
WHEN DUP_VAL_ON_INDEX THEN
RETURN -2;
WHEN INVALID_NUMBER THEN
RETURN -3;
WHEN OTHERS THEN
RETURN -4;
END;
SHOW ERRORS PROCEDURE F_SSC_Page_Map_Insert;
GRANT EXECUTE ON F_SSC_Page_Map_Insert TO B2B_USER_DBROLE;
RETURN INTEGER
EDIT: I change the arguments and received a new error related to the insert command
CREATE OR REPLACE FUNCTION F_SSC_Page_Map_Insert(
p_page_id IN INTEGER,
p_page_type IN VARCHAR2,
p_page_dcpn IN VARCHAR2)
RETURN INTEGER
IS
TABLE_DOES_NOT_EXIST exception;
PRAGMA EXCEPTION_INIT(TABLE_DOES_NOT_EXIST, -942); -- ORA-00942
BEGIN
INSERT INTO
B2BOWNER.SSC_Page_Map VALUES(
p_page_id,
p_page_type,
p_page_dcpn);
The error
Errors for FUNCTION F_SSC_PAGE_MAP_INSERT
LINE/COL ERROR
-------- -----------------------------------------------------------------
17/18 PL/SQL: ORA-00942: table or view does not exist
16/5 PL/SQL: SQL Statement ignored
The tables has been verified within the correct schema and with the correct attribute names and types
EDIT: I executed the following command to check if I have access
DECLARE
count_this INTEGER;
BEGIN
select count(*) into count_this
from all_tables
where owner = 'B2BOWNER'
and table_name = 'SSC_PAGE_MAP';
DBMS_OUTPUT.PUT_LINE(count_this);
END;
The output I received is
1
PL/SQL procedure successfully completed.
I have access to the table.
EDIT:
So I finally conducted an insert into the table via the schema using PL/SQL and it worked fine. It appears I simply do not have authority to create functions but that is an assumption.
EDIT:
Actual table DDL statement
v_create := 'CREATE TABLE ' || TABLE_NAME || ' (
PAGE_ID_NBR NUMERIC(10) NOT NULL Check(Page_ID_NBR > 0),
PAGE_TYPE VARCHAR2(50) NOT NULL,
PAGE_DCPN VARCHAR2(100) NOT NULL,
PRIMARY KEY(Page_ID_NBR, Page_Type))';
EXECUTE IMMEDIATE v_create;
COMMIT WORK;
COMMIT COMMENT 'Create Table';
When creating the TABLE under B2BOWNER, be sure to prefix the PL/SQL function with the Schema name; i.e. B2BOWNER.F_SSC_Page_Map_Insert.
I did not realize this until the DBAs pointed it out. I could have created the table under my root USER/SCHEMA and the PL/SQL function would have worked fine.
The procedure name should be in caps while creating procedure in database.
You may use small letters for your procedure name while calling from Java class like:
String getDBUSERByUserIdSql = "{call getDBUSERByUserId(?,?,?,?)}";
In database the name of procedure should be:
GETDBUSERBYUSERID -- (all letters in caps only)
This serves as one of the solutions for this problem.
you should give permission on your db
grant execute on (packageName or tableName) to user;