I am finding it increasingly common for developers and support staff not to have direct access to the PeopleSoft OwnerID schema (SYSADM) in even development environments, but using personal database logins. They need to have SELECT privilege on tables. The problem described above also occurs when table is rebuilt by Application Designer. When it is dropped the granted privileges disappear with the table.
It is certainly true that you cannot issue DDL in DDL trigger on the same object that caused the trigger to fire. You will get an error caused by a deadlock in the recursive SQL.
CREATE OR REPLACE TRIGGER gfc_grant AFTER CREATE ON sysadm.schema
DECLARE
l_cmd VARCHAR2(1000 CHAR);
BEGIN
IF ora_dict_obj_type = 'TABLE' THEN
l_cmd := 'GRANT SELECT ON '||ora_dict_obj_owner||'.'||ora_dict_obj_name||' TO gofaster';
dbms_output.put_line('DDL:'||l_cmd);
EXECUTE IMMEDIATE l_cmd;
END IF;
END;
/
show errors
set serveroutput on
DDL:GRANT SELECT ON SYSADM.T TO gofaster
CREATE TABLE t (a NUMBER)
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-30511: invalid DDL operation in system triggers
ORA-06512: at line 9Some sites have regular maintenance jobs that recreate any missing privileges.
However, there is a way to have the privileges automatically recreated soon after the table is built. You could use a DDL trigger to submit a job to the Oracle job scheduler to grant the privileges. You can't submit DDL directly via the job scheduler, so you need a procedure to which you can pass the DDL as a string parameter, and then execute it as dynamic SQL in the procedure.
CREATE OR REPLACE PROCEDURE myddl (p_ddl IN VARCHAR2) IS BEGIN EXECUTE IMMEDIATE p_ddl; END; /
Then the DDL trigger can submit a job to call this procedure with the GRANT command in the parameter.
CREATE OR REPLACE TRIGGER gfc_grant
AFTER CREATE ON sysadm.schema
DECLARE
l_jobno NUMBER;
BEGIN
IF ora_dict_obj_type = 'TABLE' THEN
dbms_job.submit(l_jobno,'myddl(''GRANT SELECT ON '||ora_dict_obj_owner||'.'||ora_dict_obj_name||' TO gofaster'');');
END IF;
END;
/
If I create this table
CREATE TABLE t (a NUMBER);
I get this job
SELECT * FROM dba_jobs
/
JOB LOG_USER
---------- ------------------------------------------------------------------------------------------
PRIV_USER
------------------------------------------------------------------------------------------
SCHEMA_USER LAST_DATE
------------------------------------------------------------------------------------------ -------------------
LAST_SEC THIS_DATE THIS_SEC NEXT_DATE
------------------------ ------------------- ------------------------ -------------------
NEXT_SEC TOTAL_TIME BRO
------------------------ ---------- ---
INTERVAL
---------------------------------------------------------------------------------------------------------------
FAILURES
----------
WHAT
---------------------------------------------------------------------------------------------------------------
60 SYSADM
SYSADM
SYSADM
19:04:52 05/03/2009
19:04:52 0 N
null
myddl('GRANT SELECT ON SYSADM.T TO gofaster');
After the job has run, which should normally only be a few seconds, I get these privileges
SELECT * FROM user_tab_privs WHERE table_name = 'T'; GRANTEE ------------------------------------------------------------------------------------------ OWNER ------------------------------------------------------------------------------------------ TABLE_NAME ------------------------------------------------------------------------------------------ GRANTOR ------------------------------------------------------------------------------------------ PRIVILEGE --------------------------------------------------------------------------------------------------------------- GOFASTER SYSADM T SYSADM SELECT
Added 2.4.2009: Following this posting it was put to me that you could get Application Designer to build scripts with the commands to add the privilege by adding a second command to the create table DDL model. See part 2.


2 comments:
The wya I handle this is slightly different:
1- create a role with the required select grants.
2- create an "access user" that everyone connects to if they want to see the tables.
3- grant the role to the access user.
4- have a login trigger on the access user that does a "alter session set current_schema=sysman/psman".
And that's it. If I need to change access rules, I change the role. And with the current_schema, no one needs to type owner.table_name and/or create synonyms.
Need to stop people accessing the system? Turn off the role and/or disable the access user id.
Nice and easy.
I didn't make it clear in the original posting, but I was granting the privilege to a role called gofaster. The grant command would have been exactly the same if I was granting the privilege to a user called gofaster.
Post a Comment