Creating a synonym for all objects in another schema - oracle

I am interested in creating a SYNONYM for another schema and all objects in them (Tables, View, Procedures, Packages, etc). Currently users are getting an error that a certain table doesn't exist. It's happening because they are running a query like SELECT * FROM mytable. If the query were SELECT * FROM myschema.mytable it would work.
Does creating public synonym make the schema available to all users or roles? Are there any security issues with granting a public synonym? Should I use a non-public synonym? We are allocating permissions to the schema via roles.
Is there a query or script that would enable this?

Yes, you probably want a public synonym. From the docs:
Specify PUBLIC to create a public synonym. Public synonyms are
accessible to all users. However each user must have appropriate
privileges on the underlying object in order to use the synonym.
I think the main security issue they mention is to not create a public synonym with the same name as an existing schema.
See also object name resolution.
There's not a simple command, but you could script it with something like this:
begin
for r in (select owner, table_name from all_tables where owner = 'MYSCHEMA')
loop
execute immediate 'create public synonym ' || r.table_name || ' for ' || r.owner || '.' || r.table_name;
end loop;
end;
/
Edit: if you want more than just tables, you can change the query to loop over all_objects instead and pick the object types you want:
begin
for r in (select owner, object_name from all_objects
where owner = 'MYSCHEMA'
and object_type in ('TABLE','VIEW','PROCEDURE','FUNCTION','PACKAGE'))
loop
execute immediate 'create public synonym ' || r.object_name
|| ' for ' || r.owner || '.' || r.object_name;
end loop;
end;
/

Related

How to grant access to role for the tables that are created today

How to grant access to role for the tables that are created today :
grant select on ( select
object_name as table_name
from sys.all_objects
where object_type = 'TABLE'
-- excluding some Oracle maintained schemas
and owner not in ('ANONYMOUS','CTXSYS','DBSNMP','EXFSYS', 'LBACSYS',
'MDSYS', 'MGMT_VIEW','OLAPSYS','OWBSYS','ORDPLUGINS', 'ORDSYS','OUTLN',
'SI_INFORMTN_SCHEMA','SYS','SYSMAN','SYSTEM', 'TSMSYS','WK_TEST','WKSYS',
'WKPROXY','WMSYS','XDB','APEX_040000', 'APEX_PUBLIC_USER','DIP',
'FLOWS_30000','FLOWS_FILES','MDDATA', 'ORACLE_OCM', 'XS$NULL',
'SPATIAL_CSW_ADMIN_USR', 'SPATIAL_WFS_ADMIN_USR', 'PUBLIC')
and created > sysdate -1
) to PSREAD_ROLE_W;
This query is not working. I am not sure how to pass the selected values in order to grant the access.
you will not run your sql successfully because you essentially need 'dynamic sql', you may need write a piece of block of pl/sql as below in SqlPlus.
begin
for tab in (select owner,object_name
from sys.all_objects
where object_type = 'TABLE'
-- excluding some Oracle maintained schemas
and owner not in ('ANONYMOUS','CTXSYS','DBSNMP','EXFSYS', 'LBACSYS',
'MDSYS', 'MGMT_VIEW','OLAPSYS','OWBSYS','ORDPLUGINS', 'ORDSYS','OUTLN',
'SI_INFORMTN_SCHEMA','SYS','SYSMAN','SYSTEM', 'TSMSYS','WK_TEST','WKSYS',
'WKPROXY','WMSYS','XDB','APEX_040000', 'APEX_PUBLIC_USER','DIP',
'FLOWS_30000','FLOWS_FILES','MDDATA', 'ORACLE_OCM', 'XS$NULL',
'SPATIAL_CSW_ADMIN_USR', 'SPATIAL_WFS_ADMIN_USR', 'PUBLIC')
loop
execute immediate 'grant select on ' || tab.owner || '.' || tab.object_name || ' to PSREAD_ROLE_W';
end loop;
end;
/
try this code with sqlplus, if your need call it from jdbc, you still need create a named procedure and then call from java code.
you can run this SQL, generate the output and execute the SQL generated.
Or the other option is to USE dynamic SQL and execute immediate to run the SQL
SELECT ' GRANT SELECT ON ' || object_name || ' to PSREAD_ROLE_W; '
from sys.all_objects obj where object_type = 'TABLE'
and created > sysdate -1

How to delete sequences and procedures during logoff trigger?

Could you please help me in a unique situation I am in. I am receiving "ORA-30511: invalid DDL operation in system triggers" when dropping sequences and procedures during logoff trigger.
I need to delete tables, sequences and procedures of users before logoff event happens. I am writing the table details in DB_OBJECTS table upon create using a separate trigger. Below is my logoff trigger - could you please help me where I am doing wrong. Dropping tables is working fine in the below code. Only Dropping sequences and procedures is giving me "ORA-30511: invalid DDL operation in system triggers" error.
CREATE OR REPLACE TRIGGER DELETE_BEFORE_LOGOFF
BEFORE LOGOFF ON DATABASE
DECLARE
USER_ID NUMBER := SYS_CONTEXT('USERENV', 'SESSIONID');
BEGIN
FOR O IN (SELECT USER, OBJECT_NAME, OBJECT_TYPE
FROM DB_OBJECTS WHERE SID = USER_ID
AND USERNAME = USER AND SYSDATE > CREATED_DTTM) LOOP
IF O.OBJECT_TYPE = 'TABLE' THEN
EXECUTE IMMEDIATE 'DROP TABLE ' || O.USER || '.' || O.OBJECT_NAME || ' CASCADE CONSTRAINTS';
ELSIF O.OBJECT_TYPE = 'SEQUENCE' THEN
EXECUTE IMMEDIATE 'DROP SEQUENCE ' || O.USER || '.' || O.OBJECT_NAME;
ELSIF O.OBJECT_TYPE = 'PROCEDURE' THEN
EXECUTE IMMEDIATE 'DROP PROCEDURE ' || O.USER || '.' || O.OBJECT_NAME;
END IF;
END LOOP;
EXCEPTION WHEN NO_DATA_FOUND THEN NULL;
END;
/
That's a simple one.
Error code: ORA-30511
Description: invalid DDL operation in system triggers
Cause: An attempt was made to perform an invalid DDL operation in a system trigger. Most DDL operations currently are not supported in system triggers. The only currently supported DDL operations are table operations and ALTER/COMPILE operations.
Action: Remove invalid DDL operations in system triggers.
That's why only
Dropping tables is working fine
succeeded.
Therefore, you can't do that using trigger.
You asked (in a comment) how to drop these objects, then. Manually, as far as I can tell. Though, that's quite unusual - what if someone accidentally logs off? You'd drop everything they created. If you use that schema for educational purposes (for example, every student gets their own schema), then you could create a "clean-up" script you'd run once class is over. Something like this:
SET SERVEROUTPUT ON;
DECLARE
l_user VARCHAR2 (30) := 'SCOTT';
l_str VARCHAR2 (200);
BEGIN
IF USER = l_user
THEN
FOR cur_r IN (SELECT object_name, object_type
FROM user_objects
WHERE object_name NOT IN ('EMP',
'DEPT',
'BONUS',
'SALGRADE'))
LOOP
BEGIN
l_str :=
'drop '
|| cur_r.object_type
|| ' "'
|| cur_r.object_name
|| '"';
DBMS_OUTPUT.put_line (l_str);
EXECUTE IMMEDIATE l_str;
EXCEPTION
WHEN OTHERS
THEN
NULL;
END;
END LOOP;
END IF;
END;
/
PURGE RECYCLEBIN;
It is far from being perfect; I use it to clean up my Scott schema I use to answer questions on various sites so - once it becomes a mess, I run that PL/SQL code several times (because of possible foreign key constraint).
Other option is to keep a create user script(s) (along with all grant statements) and - once class is over - drop existing user and simply recreate it.
Or, if that user contains some pre-built tables, keep export file (I mean, result of data pump export) and import it after the user is dropped.
There are various options - I don't know whether I managed to guess correctly, but now you have something to think about.

Issues with user/system oracle role access and permissions

I am having a bit of an odd issue when it comes to oracle roles and my schema creation code, I will do my best to describe my problem below:
On schema create a role is created using the schema name provided.
EXECUTE IMMEDIATE 'CREATE ROLE ' || USER || 'ADMIN_R';
This role is then granted to specific users associated with that schema.
DECLARE
V_ROLE_NAME CONSTANT VARCHAR2(30) := USER || 'ADMIN_R';
CURSOR C_ADMIN_USERS IS
SELECT USERNAME FROM DBUSERS WHERE ROLE = 'ADMINISTRATION';
BEGIN
FOR REC IN C_ADMIN_USERS
LOOP
EXECUTE IMMEDIATE 'GRANT ' || V_ROLE_NAME || ' TO ' || REC.USERNAME || ' WITH ADMIN OPTION';
END LOOP;
END;
Users with this role have access to a special administration package.
EXECUTE IMMEDIATE 'GRANT EXECUTE ON P_ADMINISTRATION TO ' || USER || 'ADMIN_R';
The problem is When I drop the schema it does not drop this role (belongs to oracle), so when I recreate this schema the whole process fails because this role already exists. I also can't grant access to this role without logging into the system users which I want to avoid. The simple solution would be to just drop it, but my concern in that instance is that the DBA has been using that role to grant access to additional users and potentially additional packages, which would all be lost if we just arbitrarily drop the role to recreate it.
Any assistance would be greatly appreciated.
You could surround your role create with something like this:
SELECT COUNT(*)
INTO v_count
FROM DBA_ROLES
WHERE ROLE = USER || 'ADMIN_R';
IF v_count = 0 THEN
--grant your roles
END IF;
You can grant the same privilege as many times as you like.
you can drop the role before create
declare
i int;
begin
select count(*) into i
from dba_roles where role = USER||'ADMIN_R';
if (0 != i) then
execute immediate 'drop role '||USER||'ADMIN_R';
dbms_output.put_line('Role ' ||USER||'ADMIN_R has been dropped');
end if;
execute immediate 'create role '||USER||'ADMIN_R';
dbms_output.put_line('Role ' ||USER||'ADMIN_R has been created');
end;
1st try:
Role SCMADMIN_R has been created
2nd try:
Role SCMADMIN_R has been dropped
Role SCMADMIN_R has been created

How to create multiple table synonyms in oracle 10g?

I have multiple table.
I tried to this query:
CREATE PUBLIC SYNONYM CHKWEBUSER FOR NEST.CHKWEBUSER;
But I have multiple table like 5000. SO how can I create synonym in one query?
You cannot simply create synonyms for all tables with a single command. What you need to do is to create / generate a script that will do that for you.
Here, you have a simple script that will generate a list of CREATE PUBLIC SYNONYM... commands which you can later run.
DECLARE
CURSOR cTables IS
SELECT *
FROM ALL_TABLES TAB
WHERE TAB.OWNER = 'NEST'; /* Tune the where clause to your needs */
sSql VARCHAR2(20000);
BEGIN
FOR rTable in cTables LOOP
sSql := 'CREATE PUBLIC SYNONYM ' || rTable.TABLE_NAME || ' FOR NEST.' || rTable.TABLE_NAME || ';';
DBMS_OUTPUT.PUT_LINE(sSql);
END LOOP;
END;
This script will print out commands like:
CREATE PUBLIC SYNONYM MY_TABLE FOR NEST.MY_TABLE
Additionally, instead of using DBMS_OUTPUT.PUT_LINE you can go with directly calling:
EXECUTE IMMEDIATE sSql;
instead. This will automagically create the synonyms for you.
The following statement will generate the necessary statements.
You need to spool/export the output of that statement into a SQL script and then run that script.
How you do that depends totally on which SQL client you are using. With SQL*Plus you would e.g. use the spool command.
select 'create public synonym '||table_name||' for '||owner||'.'||table_name||';'
from all_tables
where owner = 'NEST';

Grant select on a table forcing WHERE

I have a table with users data (email, name, surname, username, password..) and I want to grant each user to see only his own data (like seeing his profile). I have been trying to do it this way:
create or replace
PROCEDURE PR_OWNDATA AS
BEGIN
FOR userRow IN (SELECT COD_USUARIO, USERNAME FROM CAMP.USERS) LOOP
EXECUTE IMMEDIATE 'GRANT SELECT ON CAMP.USERS TO "' || userRow.USERNAME || '" WHERE COD_USUARIO = ' || userRow.COD_USUARIO || ';';
END LOOP;
END PR_OWNDATA;
It doesn't work (ORA 06550 "line %s, column %s:\n%s"). But I can't see where is the problem..
I have think about create a VIEW per USER in this way
CREATE VIEW userRow.USERNAME.V_DATOSALUMNO AS SELECT * FROM CAMP.USERS WHERE COD_USUARIO = ' || userRow.COD_USUARIO || ';';
But I don't know if it is the correct way..
Thank you in advance.
I don't understand the name you're giving to the view, but the code should be:
CREATE VIEW my_view_name
AS
SELECT *
FROM CAMP.USERS
WHERE COD_USUARIO = SYS_CONTEXT('USERENV', 'SESSION_USER')
Of course if you're not salting and hashing that password then you're doing it all wrong.

Resources