exec gather table stats from procedure - oracle

If I create a procedure:
CREATE OR REPLACE PROCEDURE SchameB.PRC_GATHER_STATS IS
BEGIN
SYS.DBMS_STATS.GATHER_TABLE_STATS( 'SchName', 'TableName', CASCADE => TRUE);
END;
and execute it ;
EXEC SchameB.PRC_GATHER_STATS;
this gives me error ORA-20000: Unable to analyze TABLE "SchameA"."TableName", insufficient privileges or does not exist. But this works:
EXEC SYS.DBMS_STATS.GATHER_TABLE_STATS( 'SchameA', 'TableName', CASCADE => TRUE);
The user who EXECs the procedure and the table are in different schemas.
Why am I getting an error when doing this through a procedure?

To gather statistics on an object in another schema you need the ANALYZE ANY system privilege. I appears that the user that runs your procedure has that privilege, but granted through a role. As the documentation says:
All roles are disabled in any named PL/SQL block (stored procedure,
function, or trigger) that executes with definer's rights.
You can either GRANT ANALYZE ANY directly to your user, or create the procedure with invoker's rights, as:
CREATE OR REPLACE PROCEDURE SchameB.PRC_GATHER_STATS
AUTHID CURRENT_USER IS
BEGIN
SYS.DBMS_STATS.GATHER_TABLE_STATS('SchName', 'TableName', CASCADE => TRUE);
END;
/
When you EXEC the DBMS_STATS procedure directly, it's running as an anonymous block, and those always run with invoker's rights - honouring roles.

If you want the procedure to be able to be ran by a user without the ANALYSE ANY role then you can set the AUTHID to be DEFINER
CREATE OR REPLACE PROCEDURE SchameB.PRC_GATHER_STATS
AUTHID DEFINER IS
BEGIN
SYS.DBMS_STATS.GATHER_TABLE_STATS('SchName', 'TableName', CASCADE => TRUE);
END;

Related

Insufficient INHERIT PRIVILEGES for a stored procedure ORACLE

I am having a stored procedure in user META. This SP truncates a table in user STAGE.
CREATE PROCEDURE META.sp_truncate_tablex
AUTHID CURRENT_USER
as
BEGIN
EXECUTE IMMEDIATE 'TRUNCATE TABLE STAGE.Tablex';
END;
When I run the SP I get RA-06598: insufficient INHERIT PRIVILEGES.
I have tried to make both users to DBA.
This means if I run SELECT grantee
WHERE granted_role = 'DBA'
ORDER BY grantee;
it shows me that META dn STAGE are DBA.
I have also tried: GRANT INHERIT PRIVILEGES ON USER STAGE TO META; But I still get the same error in Oracle 18.
Your problem is this clause:
AUTHID CURRENT_USER
This means the user who executes the procedure does so with their own privileges. So a user who is not META cannot run the procedure unless they have the DROP ANY TABLE privilege, in which case they don't need to run the procedure as they can truncate the table anyway.
The solution is to declare the procedure with
AUTHID DEFINER
Now the procedure executes with the privileges of its owner - META - who presumably owns the target table. Except they don't. The table is actually owned by STAGE. So STAGE needs to own the procedure as well.
As it happens, DEFINER rights are the default so we don't need to explicitly define them, except for clarity.
CREATE PROCEDURE STAGE.sp_truncate_tablex
AS
BEGIN
EXECUTE IMMEDIATE 'TRUNCATE TABLE STAGE.Tablex';
END;

As a system user I have this error: ORA-01031: insufficient privileges

I have a stored procedure for deleting partitions. Before starting, I have to delete a constraint.
I installed the stored procedure on system user. When I test the procedure I have this error: 'ORA-01031: insufficient privileges'.
This is a piece of code that I wrote:
BEGIN
EXECUTE IMMEDIATE 'ALTER TABLE USER_NAME.TABLE_NAME DISABLE CONSTRAINT CONSTRAINT_NAME';
EXCEPTION
WHEN OTHERS THEN
O_sCodError := 'NO_OK';
O_sDesError := 'Error at DISABLE CONSTRAINT_NAME: ' || SQLERRM || ';';
RETURN;
END;
Well, as I execute the stored procedure as system, I do not understand the reason for I have that error. And I think I eventually think the same error when I try to delete a partition.
Works for me on 11g XE:
SQL> show user
USER is "SCOTT"
SQL>
SQL> create table test
2 (id number constraint pk_test primary key,
3 name varchar2(20)
4 );
Table created.
SQL> connect system
Enter password:
Connected.
SQL> begin
2 execute immediate 'alter table scott.test disable constraint pk_test';
3 return;
4 end;
5 /
PL/SQL procedure successfully completed.
SQL>
Please, follow that example and execute it in your database. Post the result (by editing the question, not as a comment).
First, you should never install custom code in an Oracle default schema like SYSTEM. Put your code in a dedicated application schema. Since it contains dynamic SQL (execute immediate) you might want to consider making it an "invoker's rights" procedure, then granting execute privileges on it to the user that will execute it.
That said, in Oracle 11g whoever's privileges are used to run the PL/SQL block must have direct permissions on the underlying table, not inherited permissions through a role like DBA. If the procedure has "definer's rights" then the schema that owns the procedure must have direct privileges on the table. If "invoker's rights" then the user executing the procedure must have the privileges.
See this link for additional details:
Execute immediate within Oracle Procedure
You must grant SYSTEM account direct privilege (not with a role) to run ALTER TABLE on the target table because roles are not enabled in stored procedures by default: https://asktom.oracle.com/Misc/RolesAndProcedures.html.
Try:
grant alter any table to system;
or
grant alter table on user_name.table_name to system;

Strange ORA-942 when using DBMS_CRYPTO but table exists

This is very strange, and not easy to explain, so please bear with me.
Oracle 12.2.0.1 on Linux x86_64.
We have a user called BATCH who has minimal privileges.
CREATE USER batch IDENTIFIED BY batch
DEFAULT TABLESPACE users
QUOTA UNLIMITED ON users;
GRANT CREATE SESSION TO batch;
GRANT EXECUTE ON DBMS_CRYPTO TO batch;
The is a PLSQL package in a schema called ATLED which is :
CREATE OR REPLACE PACKAGE ALTED.the_pkh AUTHID current_user AS
PROCEDURE crttab;
END;
/
CREATE OR REPLACE PACKAGE BODY ALTED.the_pkh AS
PROCEDURE crttab IS
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE atled.the_tab AS SELECT id, DBMS_CRYPTO.HASH(cc,2) AS cc FROM ARCHIVE.table_b';
END crttab;
END;
/
We are using Code Based Access Control (CBAC - 12c feature) to restrict/control/allow certain canned actions to an otherwise toothless user, so we create a wrapper procedure, grant that a high priv role, and grant execute on that to the batch user:
CREATE OR REPLACE PROCEDURE ALTED.wrapper_crttab AS
PROCEDURE p1 IS
CURSOR c1 is SELECT * FROM SESSION_PRIVS;
BEGIN
FOR r1 IN c1 LOOP
DBMS_OUTPUT.PUT_LINE( r1.privilege );
END LOOP;
END;
BEGIN
p1;
ALTED.the_pkh.crttab;
END;
/
GRANT IMP_FULL_DATABASE TO ALTED;
GRANT IMP_FULL_DATABASE ALTED.wrapper_crttab;
GRANT EXECUTE ON ALTED.wrapper_crttab TO batch;
Now let's run it:
CONN batch/batch
SET SERVEROUTPUT ON
EXEC ALTED.wrapper_crttab;
This causes the error:
Error at line 1:
ORA-00942: table or view does not exist
The tables referenced do exist.
The call to the p1 proc confirms that all the privileges bundled with IMP_FULL_DATABASE are present, including CREATE ANY TABLE, DROP ANY TABLE, EXECUTE ANY PROCEDURE.
If I do this:
GRANT CREATE ANY TABLE TO batch;
GRANT SELECT ANY TABLE TO batch;
CONN batch/batch
EXEC EXECUTE IMMEDIATE 'CREATE TABLE atled.the_tab AS SELECT id, DBMS_CRYPTO.HASH(cc,2) AS cc FROM ARCHIVE.table_b;
This works.
If I change the CREATE TABLE stmt to remove the DBMS_CRYPTO call, it works as well.
The actual package/proc that is called creates a number of tables fine when run as above, but fails on the case when DBMS_CRYPTO is called in any CREATE TABLE stmt.
If I grant the batch user the CREATE ANY TABLE, SELECT ANY TABLE and EXECUTE ANY PROCEDURE privs directly and run the CREATE TABLE command as batch directly then that works too.
So this is not (I think) a straight ORA-942 error, but something related to a chain of privileges to DBMS_CRYPTO, and only when executed in a package stored procedure, but what exactly I do not know.
UPDATE 1
If I create a wrapper for DBMS_CRYPTO.HASH as follows:
CREATE OR REPLACE FUNCTION batch.crypto_hash ( pcc IN CLOB ) RETURN VARCHAR2 IS
BEGIN
RETURN DBMS_CRYPTO.HASH(pcc,2);
END;
/
Then replace the DBMS_CRYPTO.HASH(cc,2) in the CREATE TABLE stmt with batch.crypto_hash(cc) then it works!!!
So, DEFINITELY not a issue with grants on teh tables being referenced, but more likely something internal with the way DBMS_CRYPTO works. Perhaps it reads a look up table somewhere. I tried GRANT EXECUTE ON UTL_I18N to batch as well before this but that didn't work.
So I have a workaround, but woudl still like to know why this happens.
You're doing this:
... FROM ARCHIVE.table_b
User, who is supposed to select from that table, has to have SELECT privileges on it. It can be granted
via role
directly
If you granted the privilege via role, it works - but not in named PL/SQL procedures. It will work in anonymous PL/SQL, but not in procedures, function, packages, so - check that and, possibly, grant SELECT on table_b directly to that user.

Oracle procedure within package with alter table throws ORA-01031:insufficient privileges

I get insufficient privileges error when executing a procedure inside a package, even though appropriate access has been granted.
CREATE OR REPLACE PACKAGE DEVELOPER.DDL_PACKS
AS
PROCEDURE disbcons
AS
BEGIN
EXECUTE IMMEDIATE 'ALTER TABLE TESTER.ADDRESS DISABLE CONSTRAINT PK4';
END;
END;
GRANT ALTER ON TESTER.ADDRESS TO DEVELOPER;
EXEC developer.ddl.disbcons
EDIT:
I tried adding AUTHID DEFINER in package header. But still i get the ORA-01031:insufficient privileges error when executed with DEVELOPER. user
Execution works good if i add AUTHID CURRENT_USER and execute with the same DEVELOPER user. I do not understand why oracle does not consider relevant access when executed with AUTHID DEFINER
#Vivek you can add AUTHID DEFINER/CURRENT_USER within Package specification only, I think it will work after that, below is your package specification should be:
CREATE OR REPLACE PACKAGE DEVELOPER.DDL_PACKS AUTHID CURRENT_USER
AS
PROCEDURE disbcons;
END;

Execute dynamic DDL in PL/SQL procedure through definer role permissions

I want to perform some dynamic DDL in a procedure owned by an admin user. I'd like to execute this procedure with a technical operational user with definer rights (operational user doesn't have the create table role).
The problem is the 'create table' permission is granted to the admin user through use of a role, which doesn't allow me to execute the DDL as it seems that roles don't count in named pl/sql blocks.
create or replace
PROCEDURE test_permissions AUTHID DEFINER AS
v_query_string VARCHAR2(400 CHAR) := 'CREATE TABLE TEST(abcd VARCHAR2(200 CHAR))';
BEGIN
EXECUTE IMMEDIATE v_query_string;
END;
What I tried:
Running the procedure from a function set to AUTHID DEFINER with AUTHID CURRENT_USER on the proc (hoping the function would cascade the definer somehow)
Putting an anonymous block inside the function to execute the DDL (as roles seem to count in anonymous block)
If I set the AUTHID to CURRENT_USER, I can execute the procedure correctly with the admin user.
Is there any way I can work around this without granting CREATE TABLE directly to the admin user?
You can only set a role within a PL/SQL stored procedure/function if it has Invoker's Rights (AUTHID CURRENT_USER)(see doc). Which means that you can't use ops_user to call admin_user's procedure and then access admin_user's roles. If your DBAs insist on using a role to control the CREATE TABLE privilege, here's the approach I've seen before:
create or replace package admin_user.role_test authid current_user is
procedure test_permissions;
end role_test;
/
create or replace package body admin_user.role_test is
procedure test_permissions is
v_query_string VARCHAR2(400 CHAR) := 'begin
dbms_output.put_line(''after'');
for r in (select role from session_roles) loop
dbms_output.put_line(r.role);
end loop;
end;';
begin
dbms_output.put_line('before');
for r in (select role from session_roles) loop
dbms_output.put_line(r.role);
end loop;
DBMS_SESSION.SET_ROLE('CREATE_TABLE_ROLE IDENTIFIED BY "SECRET_PASSWORD"');
execute immediate v_query_string;
DBMS_SESSION.SET_ROLE('ALL EXCEPT CREATE_TABLE_ROLE'); -- restore defaults
end;
end role_test;
/
grant execute on admin_user.role_test to ops_user;
This will temporarily grant the role to ops_user just to execute your code. By default the ops_user should not be able to view the admin_user's package body source. You could probably wrap the package body to further protect the password. But password security aside, my biggest concern with this approach is that Oracle doesn't provide a nice way to disable a single role, so if ops_user has other password-protected roles, this code might raise an ORA-01979 when it tries to restore them.
So, there's an answer, but I'd still recommend doing what the other commenters suggested and granting CREATE TABLE to your admin user.

Resources