The typical syntax for creating a db link is as follows:
create database link remote_db_link
connect to remote_user
identified by remote_password
using 'remote_db'
But I'd like my DB link owned by another account after it's created. Is there a way to do this?
The following does NOT work:
create database link anotheruser.remote_db_link
connect to remote_user
identified by remote_password
using 'remote_db'
Sathya is correct, in that the CREATE DATABASE LINK syntax does not allow creating a database link in another schema. HOWEVER...
WORKAROUND
It IS possible to create a database link in another user's schema, as long as anotheruser has CREATE DATABASE LINK privilege, and the user you are connected as has CREATE ANY PROCEDURE privilege.
Here's the workaround I use:
create procedure anotheruser."tmp_doit_200906121431"
is
begin
execute immediate '
create database link remote_db_link
connect to remote_user
identified by remote_password
using ''remote_db'' ';
end;
/
begin
anotheruser."tmp_doit_200906121431";
end;
/
drop procedure anotheruser."tmp_doit_200906121431"
/
Let's unwind that. First, I create a procedure in the anotherusers's schema; this procedure contains the CREATE DATABASE LINK statement that I want to run.
When the procedure is executed, it runs as the owner of the procedure, such that the CREATE DATABASE LINK statement is executed by anotheruser.
The name of the procedure is not important, except that I need to make sure that it doesn't conflict with any existing object name. I use lowercase letters (enclosing the procedure name in double quotes), using "tmp" to mark this object as "temporary", and using the current yyyymmddhh24miss as the part of the procedure name. (I usually run a query of DBA_OBJECTS to check that a matching object_name does not exist.)
For a "one-off" type admin function, this is a viable workaround. I prefer this to the other alternative: saving the anotheruser's password, changing the password, connecting as the user, and resetting anotheruser's password back to the saved.)
Restrictions on DBLinks - You cannot create a database link in another user's schema, and you cannot qualify dblink with the name of a schema.
AS a sys user you can view all db links in SYS.DBA_DB_LINKS view.
That view use link$ and user$ table.
You can create new dblink as usually and it show at link$ table. Then change owner (use id from user$). commit. Done.
Related
If there is a stored procedure across different schemas (SYS, User defined Schema), which schema would be called by default if we don't mention a Schema Name.
**Schema_1**
Sample_SP
**Schema_2**
Sample_SP
**SYS**
Sample_SP
execute Sample_SP
Which schema would be executed?
It depends on how you call the procedure. If you use the simple name (meaning: not prefixed by the schema name), then Oracle will only look in the current schema. To call the procedure from any other schema, you must use the qualified name. If you call the procedure using the simple name, and a procedure by that name does not exist in your schema, you will get an error - you will not get a "default" place to look in. And, of course, if you use a qualified name to call it from a different schema, but you don't have the required privileges, you will get an error as well.
You may also create a synonym, but that can only be pointed (in the synonym definition) to one of the procedures - in one specific schema.
If you are connected as user schema_1, then its procedure would be executed.
Others might, or might not ever be executed, depending on whether their owners granted you execute privilege on their procedures and whether there are (public or private) synonyms.
But, the bottom line is: first execute your own code, then - if it doesn't exist - search for it elsewhere.
It will execute the stored procedure from connected schema.
Stored procedure from SYS will be executed if there is no user defined schema is connected as SYS is default.
I've been trying to insert data from a materialized view into a table that belongs to a different scheme using a procedure, but when I compile the procedure I get the error of: table or view doesn't exist. I have checked and I have selection and insertion privileges on that table. create or replace PROCEDURE PROCEDURE_MYPROCEDURE AS
BEGIN
INSERT INTO SCHEME.TABLE
(COLUMN1,COLUM2)
SELECT COLUMN1,COLUMN2
FROM MATERIALIZED_VIEW;
END PROCEDURE_MYPROCEDURE;
this line SCHEME.TABLEshows the message "PL/SQL: STATEMENT IGNORED", "TABLE OR VIEW DOES NOT EXIST"
The most likely cause is that you have access via a role not directly, which means you can run it in SQL but for a PLSQL procedure you need a direct privilege granted.
As per the Application Developer guide:
Privileges Required to Create Procedures and Functions
To create a stand-alone procedure or function, or package specification or
body, you must meet the following prerequisites:
You must have the CREATE PROCEDURE system privilege to create a
procedure or package in your schema, or the CREATE ANY
PROCEDURE system privilege to create a procedure or package in
another user’s schema.
Attention: To create without errors, that is, to compile the procedure
or package successfully, requires the following additional privileges:
The owner of the procedure or package must have been explicitly
granted the necessary object privileges for all objects referenced within
the body of the code; the owner cannot have obtained required
privileges through roles.
If the privileges of a procedure’s or package’s owner change, the procedure
must be reauthenticated before it is executed. If a necessary privilege to a
referenced object is revoked from the owner of the procedure (or package), the
procedure cannot be executed.
An easy way to test things is:
SQL> set role none;
SQL> "statement you want to test to see if it'll work in a procedure"
So you might just be missing some direct grants on those objects.
If the procedure is compiled on user a and the MATERIALIZED_VIEW is owned by user b. When you execute the procedure it will look for the materialized view on user a.
Put the user/schema in front of the MATERIALIZED_VIEW.
You would also need to grant select on MATERIALIZED_VIEW to user a.
I have created a synonym for a dblink.
create synonym dblink2 for dblink1
But when I query anything using the synonym instead of the dblink, I'm getting connection description for remote database not found error.
SELECT * FROM DUAL#DBLINK2
How do I query using the synonym?Edit: I know that it'll work if I create a view of the table using dblink. But my requirement is the above question.
Unfortunately creation of synonyms for dblinks is not supported. If you read the documentation on synonyms, you will find that the permitted objects for synonyms are only:
Use the CREATE SYNONYM statement to create a synonym, which is an
alternative name for a table, view, sequence, procedure, stored
function, package, materialized view, Java class schema object,
user-defined object type, or another synonym.
The reason why your second query fails is that the synomym you have created is not functioning correctly. It is not being validated properly at creation time, and you can create any sort of incorrect synonyms like that. To verify, just test the following statement:
create synonym dblink3 for no_object_with_this_name;
You will still get a response like this:
*Synonym DBLINK3 created.*
But of course nothing will work via this synonym.
I don't see the point in creating a synonym for the dblink itself. Ideally you create the synonym for the remote table using the dblink.
CREATE DATABASE LINK my_db_link CONNECT TO user IDENTIFIED BY passwd USING 'alias';
CREATE SYNONYM my_table FOR remote_table#my_db_link;
Now, you could query the remote table using the synonym:
SELECT * FROM my_table;
I'm trying to think of the business issue that gets solved by putting a synonym on a db_link, and the only thing I can think of is that you need to deploy constant code that will be selecting from some_Table#some_dblink, and although the table names are constant different users may be looking across different db_links. Or you just want to be able to swap which db_link you are operating across with a simple synonym repoint.
Here's the problem: it can't be done that way. db_link synonyms are not allowed.
Your only solution is to have the code instead reference the tables by synonyms, and set private synonyms to point across the correct db_link. That way your code continues to "Select from REMOTE_TABLE1" and you just can flip which DB_LINK you are getting that remote table from.
Is it a pain to have to set/reset 100+ private synonyms? Yep. But if it is something you need to do often then bundle up a procedure to do it for you where you pass in the db_link name and it cycles through and resets the synonyms for you.
While I understand that this question is 3+ years old, someone might be able to benefit from a different answer in the future.
Let's imagine that I have 4 databases, 2 for production and 2 for dev / testing.
Prod DBs: PRDAPP1DB1 and PRDAPP2DB1
Dev DBs: DEVAPP1DB1 and DEVAPP2DB1
The "APP2" databases are running procedures to extract and import data from the APP1 databases. In these procedures, there are various select statements, such as:
declare
iCount INTEGER;
begin
insert into tbl_impdata1
select sysdate, col1, col2, substr(col3,1,10), substr(col3,15,3)
from tbl1#dblink2; -- Where dblink2 points to DEVAPP1DB1
...
<more statements here>
...
EXCEPTION
<exception handling code here>
end;
Now that is okay for development but the dblink2 constantly needs to be changed to dblink1 when deploying the updated procedure to production.
As it was pointed out, synonyms cannot be used for this purpose.
But instead, create the db links with the same name, different connection string.
E.g. on production:
CREATE DATABASE LINK "MyDBLINK" USING 'PRDAPP1DB1';
And on dev:
CREATE DATABASE LINK "MyDBLINK" USING 'DEVAPP1DB1';
And then in the procedures, change all "#dblink1" and "#dblink2" to "#mydblink" and it all should be transparent from there.
If you are trying to have the DB link accessible for multiple schemas (users) the answer is to create a public db link
example:
CREATE PUBLIC DATABASE LINK dblink1 CONNECT TO user IDENTIFIED BY password USING 'tnsalias';
After that any schema can issue a:
SELECT * FROM TABLE#dblink1
Oracle 10g. I'm new to procedures, so maybe I'm missing something obvious.
Schema owner ABC has table T2001_WRITEOFF. First I had granted SIUD to some_update_role, and granted that role to developer user IJK. User IJK then created synonym T2001_WRITEOFF for ABC.T2001_WRITEOFF; This worked with normal SQL DML commands.
However, I read elsewhere on here that grants via a role do not work in stored procedures. I dropped the synonym from IJK; then from ABC, granted SIUD directly to IJK. From IJK, normal SQL DML works.
When I try to create a simple procedure as follows, it throws PLS-00201 identifier 'T2001_WRITEOFF' must be declared, and points to the 2nd line. This error is the same whether I use the role grants or not.
create or replace procedure woof1(
fooname in T2001_WRITEOFF.territory%TYPE, <=== error points here
bardesc IN T2001_WRITEOFF.ind_batch_submit%TYPE) IS
BEGIN
INSERT into T2001_WRITEOFF
VALUES ( fooname, bardesc);
END woof1;
/
Thanks in advance for help
JimR
In order to make role right applicable in stored procedures you might want to look at authid current_user in the oracle documentation. Also helpful: http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/subprograms.htm#LNPLS682
When trying to place a GRANT statement in an Oracle 11 stored procedure, it reports that GRANT is an unexpected symbol. Does GRANT need to be prefaced by something, or does Oracle simply disallow running GRANTS inside SPs?
It's a bad idea to use DDL (like GRANT) inside stored procedures.
You will have to use dynamic SQL (EXECUTE IMMEDIATE) to do this, but, honestly, I don't see why would you want to do this inside a stored proc.
Here's a PL/SQL stored procedure that grants object privileges (SELECT, UPDATE, etc.) on all tables owned by the current user to another user, e.g. - "appuser".
CREATE OR REPLACE PROCEDURE grant_privs
IS
CURSOR ut_cur IS SELECT table_name from user_tables;
ut_rec ut_cur%rowtype;
BEGIN
FOR ut_rec IN ut_cur
LOOP
EXECUTE IMMEDIATE 'GRANT ALL ON ' || ut_rec.table_name || ' TO appuser';
END LOOP;
END;
/
It was executed automatically after deploying database changes for a web application. The current user owns the database tables. After deploying any database changes, the stored procedure was executed to ensure that "appuser" could run SQL statements on all of the tables. The web application connected as "appuser", which had only limited system privileges, for security reasons.
This is both a solution to the problem and a solid use case for the solution.