I need to automate DDL generation on Oracle where I have read only access. When attempting to do this via dbms_metadata e.g. dbms_metadata.get_ddl('TABLE', 'SOME_TABLE') I get:
ORA-00604: error occurred at recursive SQL level 1
ORA-16000: database or pluggable database open for read-only access
Which is surprising as I am not asking to write to the database.
It is not possible for me to get more access to fix this.
However, I can successfully use Intellij or DataGrip to generate DDL https://www.jetbrains.com/datagrip/features/generation.html and the output is sufficient.
Any idea how the IDEs are doing this? Or what (if any) open source package Intellij are using?
I don't have a pluggable database but I used the following on livesql and my database and it works well.
The error indicates a read only database do you have a read/write db to test on?
Note if you are trying my example change the value of owner to meet your requirements
CREATE OR REPLACE PROCEDURE get_metadata(
p_object_type VARCHAR2,
p_object_name VARCHAR2,
p_owner VARCHAR2) authid current_user is
x clob;
begin
x :=
dbms_metadata.get_ddl(
p_object_type,
p_object_name,
p_owner);
dbms_output.put_line(x);
end;
/
BEGIN
FOR cur_r IN(
SELECT OBJECT_TYPE,
OBJECT_NAME,
OWNER
FROM ALL_OBJECTS
WHERE OWNER like 'SQL%'
AND OBJECT_TYPE IN ('TABLE', 'INDEX', 'FUNCTION', 'PROCEDURE', 'TYPE','PACKAGE', 'SEQUENCE') order by OBJECT_NAME
)
LOOP
get_metadata
(cur_r.OBJECT_TYPE,
cur_r.OBJECT_NAME,
cur_r.OWNER);
END LOOP;
END;
They might be selecting from all_source:
SELECT text
FROM all_source
WHERE owner = 'CEAADMIN'
AND name = 'APPLICATION_LIST'
AND TYPE IN ('PACKAGE', 'PACKAGE BODY')
ORDER BY TYPE, line;
View source can be retrieved from all_views. The difference is that the view is kept in a WIDEMEMO type.
SELECT *
FROM all_views
WHERE owner = 'CEAADMIN' AND view_name = 'MYLINKS_VW';
Related
I wrote a Procedure which essentially used to drop table.
It works as expected , but the problem is As this Procedure is in "DW" schema and dropping table is in "SCRATCH".
Because of this, we get insufficient privileges.
Any way we can achieve this and solve the "privilege" issue?
CREATE OR REPLACE PROCEDURE DW.PROC AUTHID CURRENT_USER IS
V_TABLE_NAME VARCHAR2(255);
V_DELETE_DT NUMBER(33);
V_LIST SYS_REFCURSOR;
BEGIN
SELECT TO_NUMBER(VALUE) INTO V_DELETE_DT FROM DW.LIST_OF_TABLE
OPEN V_LIST FOR
SELECT OBJECT_NAME FROM ALL_OBJECTS WHERE OBJECT_TYPE= 'TABLE' AND
OBJECT_NAME LIKE '%DLY_BKP%' AND CREATED <=SYSDATE - V_DELETE_DT;
LOOP
FETCH V_LIST
INTO V_TABLE_NAME;
EXIT WHEN V_LIST%NOTFOUND;
EXECUTE IMMEDIATE 'DROP TABLE SCRATCH.'||V_TABLE_NAME ;
END LOOP;
CLOSE V_LIST;
END;
To drop a table in another schema, you must do one of the following:
Be granted the "DROP ANY TABLE" system privilege. This is highly elevated and it is likely your DBAs will balk at it, but it'll work.
Create a procedure owned by the table owner that accepts a table name as a parameter and issues the drop DDL on your behalf. Grant execute privs on the procedure to your connect user. This is usually the better choice. You can further enhance it to table-drive a list of tables or table name patterns that are white-listed or black-listed for drop, whatever makes sense.
At it's most simplest:
CREATE OR REPLACE PROCEDURE scratch.drop_table(in_table_name IN varchar2)
AS
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE "'||in_table_name||'"';
END;
/
GRANT EXECUTE ON scratch.drop_table TO dw;
/
Then DW calls it:
BEGIN
scratch.drop_table('TABLE_TO_DROP');
END;
If for any reason you cannot create this procedure under the SCRATCH schema (which is an unreasonable restriction), you can create it under a privileged account like SYSTEM and also add the table owner name as an additional parameter. Then you most definitely will want to table-drive a set of white-listed owners to prevent misuse of the procedure.
I have wrote simple stored procedure in Oracle SQL Developer but found, attached ,error on execution/run step.
Here is my code:
CREATE OR REPLACE PROCEDURE EMP_NAME (EMP_ID_IN IN VARCHAR2,
EMP_NAME_OUT OUT VARCHAR2)
AS
BEGIN
SELECT first_name
INTO EMP_NAME_OUT
FROM employee
WHERE emp_id = EMP_ID_IN;
END EMP_NAME;
It also shows this error
The procedure itself seems to be OK. However, its execution is somewhat strange.
I suggest you to run it from the Worksheet itself, such as
declare
l_out employee.first_name%type;
begin
emp_name(100, l_out);
dbms_output.put_line('Result = ' || l_out);
end;
/
Though, why is it a procedure? Wouldn't a function be a better choice? E.g.
create or replace function emp_name (emp_id_in in varchar2)
return employee.first_name%type
is
retval employee.first_name%type;
begin
select first_name
into retval
from employee
where emp_id = emp_id_in;
return retval;
end;
/
You'd run it in a simple manner, as
select emp_name(100) from dual;
There's something wrong with your data dictionary. edit: you're on DB 10g, I'm guessing object_id isn't in the all arguments view. When we go to execute a stored procedure, we ask the database for some information about your code.
SELECT data_type, argument_name name
FROM all_arguments a, all_objects o
WHERE a.object_id=o.object_id
AND o.object_name=? and o.owner=? and a.package_name is NULL
order by position
The error about an invalid object_id - that's coming from this query. What version Oracle Database are you running? Can you see your PL/SQL object in ALL_OBJECTS and do your arguments show up in ALL_ARGUMENTS?
I've taken your code and modified it for the HR.EMPLOYEES table.
It works as expected.
We run some code to be able to show you the two parameters.
I put in a value of '101' for employee number or ID, and hit OK.
Then the OUT parameter is displayed below in the Log panel.
If you open your log panel (view -> log), you'll see a 'Statements' page as well. It's there that you can see ALL the code we execute on the database. That's where I went to get the SQL that's failing for you on the OBJECT_ID. Go look at that, and walk the code and confirm what's not working.
To fix this, go find an OLD copy of SQLDev that supports 10g..like maybe 2.1, OR upgrade your DB to at least 11.2.0.4.
in sqldeveloper there is a useful tool for exporting on a sql file all the object that exist on a schema.
Anyhow i am unable to find something similar for exporting the schema and user informations.
The sqldeveloper version i'm using is 3.2
Thanks, Piwakkio.
DECLARE
OBJECTDDL CLOB;
BEGIN
FOR I IN (select * from user_objects WHERE OBJECT_TYPE IN(/*WHATEVER YOU WANT*/) ) LOOP
select dbms_metadata.get_ddl(I.OBJECT_TYPE,I.OBJECT_NAME) INTO OBJECTDDL from dual;
DBMS_OUTPUT.PUT_LINE(OBJECTDDL);
END LOOP;
END;
Good Luck :)
Wow. I'm a Sql Server guy, trying to learn Oracle.
No horse in the race, just using the db that my job requires.
How do I see the results of a simple OUT SYS_REFCURSOR.
(Using TOAD 9.0.1.8)
(Oracle Environment = 10g)
Code below. Please know that using fully qualified names (schema + object_name) is the "norm" around here. (And please know I only kinda know what I'm talking about when it comes to Oracle)
CREATE OR REPLACE
PROCEDURE SYS.PROC_GET_MY_COOL_TABLES (p_recordset OUT SYS_REFCURSOR) AS
BEGIN
OPEN p_recordset FOR
SELECT
TABLE_NAME
, TABLE_TYPE
from
SYS.USER_CATALOG
where
TABLE_TYPE = 'TABLE' and TABLE_NAME NOT LIKE '%$%'
;
END PROC_GET_MY_COOL_TABLES;
/
variable myVarForARefCur refcursor;
exec SYS.PROC_GET_MY_COOL_TABLES( :myVarForARefCur );
print myVarForARefCur;
/
I need to check if a database link already exists before I create one. How can I do that?
I am writing an SQL script that starts with this:
DROP DATABASE LINK mydblink
then I create one:
CREATE DATABASE LINK mydblink
CONNECT TO testuser
IDENTIFIED BY mypswd
USING 'mypersonaldb'
I will of course get an error in the first step if the database link doesn't exists. And if I omit the first step and just go ahead and create a db link, I will again get an error saying that it already exists with the same name.
What can I do in order to check if the the database link already exists?
SELECT COUNT(1)
FROM dba_objects -- user_objects
WHERE object_type = 'DATABASE LINK'
AND object_name = 'ARGUS51P';
For example (untested):
declare
l_link_cnt pls_integer := 0;
l_sql varchar2(32767);
begin
-- link creation sql (fill in details of how you want this created)
l_sql := 'create public database link ...';
select count(1)
into l_link_cnt
from dba_objects
where object_type = 'DATABASE LINK'
and object_name = 'SOME_LINK';
-- create link if it doesn't exist yet
if (l_link_cnt = 0) then
-- create link
execute immediate l_sql;
end if;
end;
Oracle has no way to test for existence before a DROP or CREATE. (Well, ok, you could write some PL/SQL, but, that's probably more trouble than it's worth.) In Oracle scripting, it's pretty standard to simply do both the DROP and the CREATE in a script. If the DROP errors out, so be it. It won't affect execution of the script.
-Mark