Drop user cascade in Oracle - sql

I need to be able to drop a specific user (which may have active sessions) from the batch without any user interaction. I don't care about active sessions and want them to be dropped and rolled back. For Microsoft SQL i would do similar task with a single line:
osql -E -S localhost -b -Q "use master if ((select name from sysdatabases where name='%DB%') is not null) begin alter database [%DB%] set single_user with rollback immediate drop database [%DB%] end"
How do i do it for Oracle (10g XE on Windows)?
My current batch is:
sqlplus sys/*** as SYSDBA #delete1.sql >delete.log
sqlplus sys/***#XE as SYSDBA #delete2.sql >>delete.log
where delete1.sql:
startup force;
exit;
and delete2.sql:
drop user MYUSER cascade;
exit;
This is ugly as hell and takes too long comparing to the split second of MSSQL solution.

It should work if you use the following script (here named drop_user_with_active_sessions.sql):
set verify off
begin
for s in (
select
sid, serial#
from
v$session
where
username = '&1'
) loop
execute immediate
'alter system kill session ''' ||
s.sid || ',' ||
s.serial# || ''' immediate';
end loop;
execute immediate 'drop user &1';
end;
/
exit
And the use it with
sqlplus username/password#instance #c:\path\to\drop_user_with_active_session.sql MYUSER

you can do Oracle SQL via the command prompt and then do your cascade drop user.
I would recommend creating a sql script and executing it from the command line.
then you can wrap up command line text in your cmd/batch file.
but if you would like Oracle to handle the entire process I would recommend looking into the job/schedule environment

In addition to "alter system kill session" mentioned above I've also needed to preface the kill session with something like:
execute immediate 'ALTER SYSTEM DISCONNECT SESSION ''' ||
to_char(s.sid) || ', ' || to_char(s.serial#) || ''' IMMEDIATE'

It's a very, very bad idea to take a construct from one Database platform and assume I can run the exact same thing on a different platform. For example. Oracle has Create OR REPLACE procedure. MSSS isn't quite so simple. MSSS you can make a "temp" table with #name, in Oracle we use DDL. While dropping a user to recreate a fresh environment may have been the simplest approach on MSSS, perhaps there's a more Oracle-centric way to accomplish the same thing. It's a very good idea to ask for help on how to accomplish a task instead of why your way isn't working.
First, does the app being tested do DDL? to the tables and other objects?
If it only changes data, they way Oracle prefers apps to work, then why do you have to recreate all the objects. You just need to get the data back to the starting point.
Have you looked into Flashback Database? You should be able to create a restore point... do whatever you want and then flashback the database to that point in time.

Related

Unable to create DB2 Procedure through command line

I am trying to create a procedure to do a blanket revoking of executeauth for procedures from a schema. This is in line with trying to secure a non-restricted database.
CREATE PROCEDURE PROC_REV
LANGUAGE SQL
MODIFIES SQL DATA
BEGIN
DECLARE v_NAME VARCHAR(400);
FOR v1 AS
c1 CURSOR FOR
select specificname from SYSCAT.ROUTINEAUTH where grantee='PUBLIC' and schema='SYSPROC' and routinetype='P'
DO
SET v_NAME = specificname;
SET v_GrantQuery = 'revoke execute on specific procedure '|| v_NAME ||' from PUBLIC';
EXECUTE IMMEDIATE v_GrantQuery;
END FOR;
END#
and this is the command I run to process the file with the code above.
db2 -td# -svf RoutineAuthRevoke.db2
However, I keep running into this error
SQL0553N An object cannot be created with the schema name "SYSFUN ". LINE NUMBER=1. SQLSTATE 42939
I'm fairly new to DB2 and this is my first foray into writing db2 procedure scripts. Would anyone be able to spot the "SYSFUN " because I sure as hell can't. The only other way I can revoke 310 entries from SYSPROC for PUBLIC is through a batch file and I figured, procedures might be a cleaner way of achieving this. I would really appreciate any help with either this error or with the code itself.
A number of problems.
You can't create a routine in the SYSFUN schema as the error message shows. You get this message because the statement VALUES CURRENT SCHEMA returns SYSFUN in your session. You must either run the SET SCHEMA SOME_VALID_SCHEMA_NAME statement before CREATE or use fully qualified routine name like SOME_VALID_SCHEMA_NAME.PROC_REV.
Variable v_GrantQuery is not defined in the routine.
According to the syntax of REVOKE (routine privileges) statement, you should generate the REVOKE statement using fully qualified routine name and with RESTRICT clause at the end. The easiest way to do it with a compound statement (you don't need to create a routine for that):
BEGIN
FOR v1 AS
select 'REVOKE EXECUTE ON SPECIFIC PROCEDURE "' || schema ||'"."'|| specificname || '" FROM PUBLIC RESTRICT' AS STMT
from SYSCAT.ROUTINEAUTH
where grantee='PUBLIC' and schema='SYSPROC' and routinetype='P'
DO
EXECUTE IMMEDIATE v1.STMT;
END FOR;
END#

Oracle display all sql query run against DB by application

I have an old appliation/executable that loads data to Oracle DB that we are reverse engineering. We'd like to see all the sql generated by the application without stepping through source code. The source code has many different versions and may not match the executable.
select v$sql.last_load_time, v$sql.sql_text
from v$sql
order by v$sql.last_load_time desc
First, you will need help from DBA to:
grant permission to select from table v$sql.
ALTER SYSTEM SET sql_trace = true SCOPE=MEMORY; when done
ALTER SYSTEM SET sql_trace = false SCOPE=MEMORY;
select sid, serial#, machine from sys.v_$session ; find the sid and serial# for your machine and input to the next command
execute sys.dbms_system.set_sql_trace_in_session(sid, serial#, true);
flush the cache by executing following commands:
alter system flush buffer_cache;
alter system flush shared_pool;

Oracle 11g DB link usage

We are migrating from oracle 11g to 12c. We have a number of DB links created in 11g db but we're not sure whether they are really in use or not.
Since its a production environment we cannot disable the DB links and wait for some jobs to fail.
Is there any way to find out whether particular DB links are in use or not?
One of the crude way I was thinking is, writing a script to loop every 5 minutes gv$sql and search for DB link names in a query and log it. The script will run for a few days.
Is there any other way to find out?
This will search all_source for every link that is found in all_db_links.
begin
for c_links in (select '#'||db_link as db_link from ALL_DB_LINKS)
loop
dbms_output.put_line('search for link: '||c_links.db_link);
for c_source in (select * from all_source s
where upper(s.text) like '%'||c_links.db_link||'%')
loop
dbms_output.put_line('link '||c_links.db_link || 'is used in: ' || c_source.name);
end loop;
end loop;
end;
This could help you identify which links are referenced in procedures, functions and packages.

How to pass a bash variable to sqlplus and then pass that output to another variable

So what I'm trying to do is to clear the audit logs of the PDB in an Oracle database. The name of the PDB can be different each time, so I cannot use tnsnames to sqlplus directly into the PDB to do this. I'm passing commands into bash and then passing those into a SQLPLUS command. Each of these work except for one and I can't seem to figure out how to get it to work.
My code is
AUDIT="DELETE FROM SYS.AUD$ WHERE NTIMESTAMP# < sysdate-30;"
FINDPDB="select pdb_name from dba_pdbs where pdb_name != 'PDB\$SEED';"
ALTER="alter session set container=$FINDPDB;"
sqlplus -S /nolog <<EOF1
connect / as sysdba
set echo off feedback off head off pages 0
set serveroutput on
$FINDPDB
$ALTER
$AUDIT
exit;
EOF1
The error I keep getting is
alter session set container=select pdb_name from dba_pdbs where pdb_name != 'PDB$SEED';
*
ERROR at line 1:
ORA-65015: missing or invalid container name
This tells me that it's not passing the output of the select statement to $FINDPDB, but rather the actual select statement itself.
Is there a way I can pass this value to the ALTER variable and have it alter the session and clear the sys.aud$ table?
The error I keep getting is
alter session set container=select pdb_name from dba_pdbs where pdb_name != 'PDB$SEED';
*
ERROR at line 1:
ORA-65015: missing or invalid container name
This tells me that it's not passing the output of the select statement to $FINDPDB, but rather the actual select statement itself.
I don't see why you would expect this to pass the output of the SELECT query into $FINDPDB. You're putting together a big long string which bash passes to the standard input of sqlplus and then writes to stdout the output from sqlplus. At no point is bash picking out certain lines of the sqlplus output and putting them into shell variables.
In fact, try adding echo $ALTER to your bash script before you call sqlplus. You will quite probably find that the output is
alter session set container=select pdb_name from dba_pdbs where pdb_name != 'PDB$SEED';
If so, then bash has already done the substitution you didn't want before you've even started sqlplus.
You seem to want bash and sqlplus to have some kind of back-and-forth dialog. I would give up on this approach. Instead of trying to put the PDB name into a shell variable, I would put it into a sqlplus substitution variable. I would try something like the following (not tested):
sqlplus -S /nolog <<"EOF1"
connect / as sysdba
set echo off feedback off head off pages 0
set serveroutput on
column pdb_name new_value pdb
select pdb_name from dba_pdbs where pdb_name != 'PDB\$SEED';
alter session set container = &pdb.;
delete from sys.aud$ where ntimestamp# < sysdate - 30;
exit;
EOF1
We use column pdb_name new_value pdb to set the substitution variable pdb to the next value to be selected from a column named pdb_name. We then run a select query to fetch the PDB name and hence store it in pdb. Once we've got this value in a substitution variable, we can then issue the alter session statement to change the PDB and finally the delete statement to delete data from the PDB.
I'm tempted to avoid the use of a PL/SQL block for this, as has been suggested in another answer. I would prefer that the delete statement is parsed after the PDB is changed as I would want to be sure that the data from the 'correct' PDB is being deleted. My concern with using PL/SQL for this is that the PL/SQL compiler would determine which table to delete from when the block is parsed, which would be before it runs the block, and hence before it executes the alter session statement to change the PDB. However, I don't know PDBs and CDBs in Oracle 12c well enough to say whether this is a genuine problem or unfounded nonsense.
I don't have access to a pluggable Oracle 12c database to run something like this against, so I can't tell you whether this script works. If not, hopefully it should give you an idea of where to go.
I have no Oracle instance at hand but I see two ways to do this :
Make many connections through SQL*Plus
First, to retrieve pdb_name.
Second, to set container and delete audits.
Uses a single SQL*Plus but uses two named pipes
One to send generated SQL commands
Second to read SQL*Plus output
As alternative way I should have used a "real" programming language (Ruby, Python, JavaScript) which are better dedicated to deal with data read from database.
EDIT: After some search, it mays be done in PL/SQL
DECLARE
v_pdb_name VARCHAR2(255);
BEGIN
SELECT pdb_name INTO v_pdb_name FROM dba_pdbs WHERE pdb_name != 'PDB\$SEED';
EXECUTE IMMEDIATE 'ALTER SESSION SET container='||v_pdb_name;
DELETE FROM sys.aud$ WHERE ntimestamp# < sysdate-30;
END;
/

How best can I recreate an Oracle database?

Oracle 11gR2 (x86 Windows):
I have a db with 250 tables with indexes and constraints. I need to re-create these tables, indexes and constraints in a new db and load the data. I need to know how to do the following in SQL Plus and/or SQL Developer, unless there's a magical utility that can automate all of this. Thanks in advance!
Unload (export) all the data from the 250 tables.
Create an sql script file containing the CREATE TABLE statements for the 250 tables.
Create an sql script file containing the CREATE INDEX statements for the 250 tables.
Create an sql script file containing the ALTER TABLE ADD CONSTRAINT statements for the 250 tables.
Run the script to create the tables in a new db.
Load the exported data into the tables in the new db.
Run the script to create all the indexes.
Run the script to add all the contraints.
EDIT: I'm connected to the remote desktop which links to the source db on a Windows Server 2008. The remote only has an Oracle client installed. For security reasons, I'm not allowed to link directly from my local computer to the Win Server, so can I dump the whole source db to the remote then zip it to my local target machine? I'm trying to replicate the entire db on my computer.
Starting from Oracle 10g, you could use the Data Pump command-line clients expdb and impdb to export/import data and/or schema from one DB to an other. As a matter of fact, those two command-line utilities are only wrappers that "use the procedures provided in the DBMS_DATAPUMP PL/SQL package to execute export and import commands, using the parameters entered at the command line." (quoted from Oracle's documentation)
Given your needs, you will have to create a directory then generate a full dump of your database using expdb:
SQL> CREATE OR REPLACE DIRECTORY dump_dir AS '/path/to/dump/folder/';
sh$ expdp system#db10g full=Y directory=DUMP_DIR dumpfile=db.dmp logfile=db.log
As the dump is written using some binary format, you will have to use the corresponding import utility to (re)import your DB. Basically replacing expdb by impdb in the above command:
sh$ impdp system#db10g full=Y directory=DUMP_DIR dumpfile=db.dmp logfile=db.log
For simple table dump, use that version instead:
sh$ expdp sylvain#db10g tables=DEPT,EMP directory=DUMP_DIR dumpfile=db.dmp logfile=db.log
As you noticed, you can use it with your standard user account, provided you have access to the given directory (GRANT READ, WRITE ON DIRECTORY dump_dir TO sylvain;).
For detailed usage explanations, see
http://www.oracle-base.com/articles/10g/oracle-data-pump-10g.php.
If you can create a database link from your local database to the one that currently contains the data, you can use the DBMS_DATAPUMP package to copy the entire schema. This is an interface to Datapump (as #Sylvain Leroux mentioned) that is callable from within the database.
DECLARE
dph NUMBER;
source_schema VARCHAR2 (30) := 'SCHEMA_TO_EXPORT';
target_schema VARCHAR2 (30) := 'SCHEMA_TO_IMPORT';
job_name VARCHAR2 (30) := UPPER ('IMPORT_' || target_schema);
p_parallel NUMBER := 3;
v_start TIMESTAMP := SYSTIMESTAMP;
v_state VARCHAR2 (30);
BEGIN
dph :=
DBMS_DATAPUMP.open ('IMPORT',
'SCHEMA',
'DB_LINK_NAME',
job_name);
DBMS_OUTPUT.put_line ('dph = ' || dph);
DBMS_DATAPUMP.metadata_filter (dph,
'SCHEMA_LIST',
'''' || source_schema || '''');
DBMS_DATAPUMP.metadata_remap (dph,
'REMAP_SCHEMA',
source_schema,
target_schema);
DBMS_DATAPUMP.set_parameter (dph, 'TABLE_EXISTS_ACTION', 'REPLACE');
DBMS_DATAPUMP.set_parallel (dph, p_parallel);
DBMS_DATAPUMP.start_job (dph);
DBMS_DATAPUMP.wait_for_job (dph, v_state);
DBMS_OUTPUT.put_line ('Export/Import time: ' || (SYSTIMESTAMP - v_start));
DBMS_OUTPUT.put_line ('Final state: ' || v_state);
END;
The script above actually copies and renames the schema. If you want to keep the same schema name, I believe you'd just remove the metadata_remap call.
SQL Developer can help with #1 by creating INSERT statements with a formatted query result:
Select /*insert*/ *
from My_Table;