I am trying to access a sequence that is:
A. Located in another schema
B. Is actually a synonym to another database through a dblink.
What works:
select schema.sequence#dblink.nextval from dual;
What doesn't work:
select schema.synonym.sequence.nextval from dual;
The above returns a '%s: invalid identifier'
Is it possible to access the remote sequence without using the dblink annotation?
Yes, it is possible to use synonym for remote sequence object.
Database 1
SQL> conn jay
SQL> create sequence myseq increment by 1;
Sequence created.
Database 2
SQL> conn jay
SQL> create database link dbl_db1 connect to jay identified by jay using 'DB1';
Database link created.
SQL> create synonym myseq_syno for jay.myseq#dbl_db1;
Synonym created.
SQL> select myseq_syno.nextval from dual;
NEXTVAL
----------
1
Related
Oracle Database 12c Standard Edition Release 12.2.0.1.0 - 64bit Production
I'm getting the above message when trying to create a package.
I can simulate with a very simple procedure and select statement.
My understanding is that have SQL select access for a user does not translate to PL/SQL (package) access for the same user, and that an option is to use roles. This has not worked for me.
This is all done with the same user (not apex_180100).
Showing the issue:
This SQL works. It doesn't make sense, but proves that I can select from the tables.
SELECT 1
FROM apex_180100.wwv_flow_activity_log l,
apex_180100.wwv_flow_worksheet_rpts r
WHERE l.ir_report_id IS NOT NULL
AND l.flow_id = 100
AND l.worksheet_id = r.worksheet_id
AND l.ir_report_id = r.id
AND l.flow_id = r.flow_id
AND l.step_id = r.page_id;
I granted select to a role
GRANT SELECT ON apex_180100.wwv_flow_worksheet_rpts TO PRIV_FULL_TABLE;
GRANT SELECT ON apex_180100.wwv_flow_activity_log TO PRIV_FULL_TABLE;
I grant my role to my procedure (ultimately I will grant to my package)
GRANT PRIV_FULL_TABLE TO PROCEDURE p_test;
I get an error when creating this simple sample procedure.
create OR REPLACE procedure p_test is
V_TEST NUMBER;
begin
SELECT 1
INTO V_TEST
FROM apex_180100.wwv_flow_activity_log l,
apex_180100.wwv_flow_worksheet_rpts r
WHERE l.ir_report_id IS NOT NULL
AND l.flow_id = 100
AND l.worksheet_id = r.worksheet_id
AND l.ir_report_id = r.id
AND l.flow_id = r.flow_id
AND l.step_id = r.page_id;
end;
PL/SQL: ORA-01031: insufficient privileges compilation error
Hm, there's something strange in what you are saying. Usually we grant privileges to users, not procedures.
SQL> create procedure p_test as begin
2 null;
3 end;
4 /
Procedure created.
SQL> create role priv_full_table;
Role created.
SQL> grant priv_full_table to procedure p_test;
grant priv_full_table to procedure p_test
*
ERROR at line 1:
ORA-00991: only MAC privileges may be granted to procedures
SQL>
Apart from that, if I understood you correctly, issue is exactly what you thought that solves it: privileges granted to roles won't work in named stored procedures. p_test is a named procedure:
create OR REPLACE procedure p_test is ...
which means that you'll have to grant those privileges directly to user which will be using them.
Thanks to #Littlefoot
I used a workaround. My procedure is relatively simple, I wanted to insert into a custom table from my "problem" tables. I wanted this to be called by an hourly DB job.
As I can select and insert in SQL, but not PL/SQL procedures, I used a SQL script instead of datbase procedure.
i.e I converted my package into a series of SQL statements. I stored this sql script on the server and ran as a DBA job executable.
Not ideal.
PS 'execute immediate' doesn't work either.
I have a QUEUE_OWNER schema that has some queues. When I connect the application to that data source everything works fine and the app can read the from the queues.
I want to create a _USER schema that has access to the queues so I can connect the app to it and not directly to the _OWNER schema.
This is what I tried:
BEGIN
FOR Q IN (SELECT * FROM ALL_QUEUES WHERE owner = 'AQ_OWNER') LOOP
DBMS_OUTPUT.PUT_LINE('queue = ' ||Q.NAME);
DBMS_AQADM.GRANT_QUEUE_PRIVILEGE('ALL','AQ_OWNER.'||Q.NAME ,'AQ_USER',FALSE);
END LOOP;
END;
but when I put a message in the queue nothing happens in the app.
How about a little help of your DBA?
This is what my user SCOTT sees in all_queues:
SQL> select owner, name from all_queues;
OWNER NAME
------------------------------ ------------------------------
SYS SRVQUEUE
SYS SCHEDULER_FILEWATCHER_Q
SYS SCHEDULER$_EVENT_QUEUE
However, I'd like to see some other data. SYS almighty sees it all:
SQL> show user
USER is "SYS"
SQL> select owner, name from dba_queues;
OWNER NAME
------------------------------ ------------------------------
SYS SYS$SERVICE_METRICS
SYS AQ$_SYS$SERVICE_METRICS_TAB_E
SYSTEM DEF$_AQERROR
SYSTEM AQ$_DEF$_AQERROR_E
SYSTEM DEF$_AQCALL
SYSTEM AQ$_DEF$_AQCALL_E
SYS AQ$_KUPC$DATAPUMP_QUETAB_E
<snip>
Still connected as SYS, I'll create a view which show data only for owner I choose (there's nothing much to choose in my XE database so I'll use SYSTEM-owned values). Then grant select privilege to SCOTT:
SQL> create or replace view v_dba_queues as
2 select name
3 from dba_queues
4 where owner = 'SYSTEM';
View created.
SQL> grant select on v_dba_queues to scott;
Grant succeeded.
Back to SCOTT: to make my life simpler, I'll create a synonym first:
SQL> connect scott/tiger
Connected.
SQL> create synonym v_dba_queues for sys.v_dba_queues;
Synonym created.
Finally:
SQL> select * from v_dba_queues;
NAME
------------------------------
DEF$_AQERROR
AQ$_DEF$_AQERROR_E
DEF$_AQCALL
AQ$_DEF$_AQCALL_E
SQL>
Basically, you'd do the same; it's just that your view would contain data for owner = 'QUEUE_OWNER'. See if it helps.
My question is related to the meaning of USER in Oracle.
We have a database with many user, but R1S contains almost all the tables, sequence, etc. We want to load new tables data, but we also need to update the sequence values to be in phase with the table data.
ORA-31684: Object type USER:"R1S" already exists
ORA-31684: Object type SEQUENCE:"R1S"."RS2QNUNI" already exists
. . imported "R1S"."RSCIN" 13.16 MB 150346 rows
in the impdp I've noticed that the sequences hadn't been updated because they already exists. We want to force the load of this kind of data.
I've thought in do a DROP USER R1S CASCADE;
This USER used in the drop command is an SCHEMA. With the DROP USER command we are deleting the schema called R1S.
I've said that because in the impdp documentation i see i can force schme import :
SCHEMAS=R1S
Or the basic command will do the same job ?
impdp xxxxxx/******** FULL=Y CONTENT=ALL directory=EXPLOIT_DUMP_DIR dumpfile=expdp_X.exp LOGFILE=impdp_X.log
Simply put, schema = user + its objects (tables, views, procedures, sequences, ...) so - when you drop user, all its objects are also dropped.
If you are happy with the rest of import results (i.e. tables are correctly imported), and if there are not that many sequences there, perhaps it would be simpler to
recreate sequences (drop + create), or
alter
those sequences. The first option is easy, while the second requires a few commands. Increment it so that it reaches desired value, fetch from it, reset increment to its previous value (1, by default). Here's an example:
SQL> select s.nextval from dual;
NEXTVAL
----------
15028
SQL> alter sequence s increment by 100000;
Sequence altered.
SQL> select s.nextval from dual;
NEXTVAL
----------
115028
SQL> alter sequence s increment by 1;
Sequence altered.
SQL> select s.nextval from dual;
NEXTVAL
----------
115029
SQL> select s.nextval from dual;
NEXTVAL
----------
115030
SQL>
I'm able to call a PL/SQL procedure and package over a real database link fine, but cannot seem to do so over a loopback database link (a database link referring to a schema in the same database, used for testing purposes), in two different databases.
Is there a trick that is required in order to execute remote plsql packages/procedures/functions over a loopback database link?
Local database (foo):
CREATE DATABASE LINK MATTHEW#INST1 CONNECT TO bar IDENTIFIED BY password USING 'MATTHEW';
-- this works fine, as well as selecting from other tables
SELECT * FROM dual#MATTHEW#INST1;
Remote database (bar schema):
create package test_pkg
is
PROCEDURE test_proc;
end;
/
create package body test_pkg
is
procedure test_proc
is
begin
dbms_output.put_line('hello');
end;
end;
/
create procedure test_proc
is
begin
dbms_output.put_line('hello');
end;
/
create or replace function ff return number
is
begin
return 55;
end;
/
Local database (foo)
BEGIN
test_proc#MATTHEW#INST1;
END;
/
Error report:
ORA-06550: line 2, column 5:
PLS-00201: identifier 'TEST_PROC#MATTHEW#INST1' must be declared
BEGIN
test_pkg.test_proc#MATTHEW#INST1;
END;
/
Error report:
ORA-06550: line 2, column 5:
PLS-00201: identifier 'TEST_PKG.TEST_PROC#MATTHEW#INST1' must be declared
select ff#MATTHEW#INST1 from dual;
ORA-00904: "FF": invalid identifier
00904. 00000 - "%s: invalid identifier"
*Cause:
*Action:
Apparently, packages/procedures/functions created over a loopback database link need to be granted to the caller.
-- As the Bar schema
GRANT EXECUTE on test_proc TO foo;
GRANT EXECUTE on test_pkg TO foo;
GRANT EXECUTE on ff to foo;
Of course, this isn't necessary at all on a true database link across two databases, so why is it necessary here?
Looking at the documenation (Scroll down to "Global Name as a Loopback Database Link"):
You can use the global name of a database as a loopback database link without explicitly creating a database link. When the database link in a SQL statement matches the global name of the current database, the database link is effectively ignored.
For example, assume the global name of a database is db1.example.com. You can run the following SQL statement on this database:
SELECT * FROM hr.employees#db1.example.com;
In this case, the #db1.example.com portion of the SQL statement is effectively ignored.
So it appears that Oracle doesn't even use the loopback, thus explaining why grants are required.
Can we see a full top to bottom script? I can't reproduce that error on my db
SQL> create user foo identified by foo;
User created.
SQL> create user bar identified by bar;
User created.
SQL> grant create session, create procedure, create database link to foo;
Grant succeeded.
SQL> grant create session, create procedure, create database link to bar;
Grant succeeded.
SQL>
SQL> conn foo/foo
Connected.
SQL> create database link matthew#inst1 connect to bar identified by bar using 'db122';
Database link created.
SQL> select * from dual#matthew#inst1;
D
-
X
1 row selected.
SQL>
SQL> conn bar/bar
Connected.
SQL> create or replace
2 procedure my_proc is
3 begin
4 null;
5 end;
6 /
Procedure created.
SQL> conn foo/foo
Connected.
SQL> BEGIN
2 my_proc#MATTHEW#INST1;
3 END;
4 /
PL/SQL procedure successfully completed.
SQL>
Using this command, I am able to create a table from another schema, but it does not include triggers. Is it possible to create a table from another schema, including triggers?
create table B.tablename unrecoverable as select * from A.tablename where 1 = 0;
First option is to run CREATE script for those objects, if you have a code repository. I suppose you don't.
If you use any GUI tool, things are getting simpler as they contain the SCRIPT tab that enables you to copy code from source and paste it into target user.
If you're on SQLPlus, it means that you should, actually, know what you're supposed to do. Here's a short demo.
SQL> connect hr/hr#xe
Connected.
SQL> create table detail (id number);
Table created.
SQL> create or replace trigger trg_det
2 before insert on detail
3 for each row
4 begin
5 :new.id := 1000;
6 end;
7 /
Trigger created.
SQL>
SQL> -- you'll have to grant privileges on table to another user
SQL> grant all on detail to scott;
Grant succeeded.
Connect as SCOTT and check what we've got:
SQL> connect scott/tiger#xe
Connected.
SQL> -- now, query ALL_SOURCE and you'll get trigger code
SQL> set pagesize 0
SQL> col text format a50
SQL> select text from all_source where name = 'TRG_DET' order by line;
trigger trg_det
before insert on detail
for each row
begin
:new.id := 1000;
end;
6 rows selected.
SQL>
Yet another option is to export & import table, which will get the trigger as well (I've removed parts that aren't relevant, as Oracle database version):
C:\>exp hr/hr#xe tables=detail file=detail.dmp
About to export specified tables via Conventional Path ...
. . exporting table DETAIL 0 rows exported
Export terminated successfully without warnings.
C:\>imp scott/tiger#xe file=detail.dmp full=y
. importing HR's objects into SCOTT
. importing HR's objects into SCOTT
. . importing table "DETAIL" 0 rows imported
Import terminated successfully without warnings.
C:\>
Check what's imported (should be both table and trigger):
SQL> desc detail
Name Null? Type
----------------------------------------- -------- ---------------
ID NUMBER
SQL> select * From detail;
no rows selected
SQL> insert into detail (id) values (-1);
1 row created.
SQL> select * From detail;
ID
----------
1000
SQL>
Cool; even the trigger works.
There might be some other options, but these 4 should be enough to get you started.