I need to quickly (and forcibly) kill off all external sessions connecting to my oracle database without the supervision of and administrator.
I don't want to just lock the database and let the users quit gracefully.
How would I script this?
This answer is heavily influenced by a conversation here: http://www.tek-tips.com/viewthread.cfm?qid=1395151&page=3
ALTER SYSTEM ENABLE RESTRICTED SESSION;
begin
for x in (
select Sid, Serial#, machine, program
from v$session
where
machine <> 'MyDatabaseServerName'
) loop
execute immediate 'Alter System Kill Session '''|| x.Sid
|| ',' || x.Serial# || ''' IMMEDIATE';
end loop;
end;
I skip killing sessions originating on the database server to avoid killing off Oracle's connections to itself.
As SYS:
startup force;
Brutal, yet elegant.
Before killing sessions, if possible do
ALTER SYSTEM ENABLE RESTRICTED SESSION;
to stop new sessions from connecting.
I've been using something like this for a while to kill my sessions on a shared server. The first line of the 'where' can be removed to kill all non 'sys' sessions:
BEGIN
FOR c IN (
SELECT s.sid, s.serial#
FROM v$session s
WHERE (s.Osuser = 'MyUser' or s.MACHINE = 'MyNtDomain\MyMachineName')
AND s.USERNAME <> 'SYS'
AND s.STATUS <> 'KILLED'
)
LOOP
EXECUTE IMMEDIATE 'alter system kill session ''' || c.sid || ',' || c.serial# || '''';
END LOOP;
END;
If you want to stop new users from connecting, but allow current sessions to continue until they are inactive, you can put the database in QUIESCE mode:
ALTER SYSTEM QUIESCE RESTRICTED;
From the Oracle Database Administrator's Guide:
Non-DBA active sessions will continue
until they become inactive. An active
session is one that is currently
inside of a transaction, a query, a
fetch, or a PL/SQL statement; or a
session that is currently holding any
shared resources (for example,
enqueues). No inactive sessions are
allowed to become active...Once all
non-DBA sessions become inactive, the
ALTER SYSTEM QUIESCE RESTRICTED
statement completes, and the database
is in a quiesced state
Additional info
Important Oracle 11g changes to alter session kill session
Oracle author Mladen Gogala notes that an # sign is now required to
kill a session when using the inst_id column:
alter system kill session '130,620,#1';
http://www.dba-oracle.com/tips_killing_oracle_sessions.htm
Try trigger on logon
Insted of trying disconnect users you should not allow them to connect.
There is and example of such trigger.
CREATE OR REPLACE TRIGGER rds_logon_trigger
AFTER LOGON ON DATABASE
BEGIN
IF SYS_CONTEXT('USERENV','IP_ADDRESS') not in ('192.168.2.121','192.168.2.123','192.168.2.233') THEN
RAISE_APPLICATION_ERROR(-20003,'You are not allowed to connect to the database');
END IF;
IF (to_number(to_char(sysdate,'HH24'))< 6) and (to_number(to_char(sysdate,'HH24')) >18) THEN
RAISE_APPLICATION_ERROR(-20005,'Logon only allowed during business hours');
END IF;
END;
I found the below snippet helpful. Taken from: http://jeromeblog-jerome.blogspot.com/2007/10/how-to-unlock-record-on-oracle.html
select
owner||'.'||object_name obj ,
oracle_username||' ('||s.status||')' oruser ,
os_user_name osuser ,
machine computer ,
l.process unix ,
s.sid||','||s.serial# ss ,
r.name rs ,
to_char(s.logon_time,'yyyy/mm/dd hh24:mi:ss') time
from v$locked_object l ,
dba_objects o ,
v$session s ,
v$transaction t ,
v$rollname r
where l.object_id = o.object_id
and s.sid=l.session_id
and s.taddr=t.addr
and t.xidusn=r.usn
order by osuser, ss, obj
;
Then ran:
Alter System Kill Session '<value from ss above>'
;
To kill individual sessions.
To answer the question asked,
here is the most accurate SQL to accomplish the job,
you can combine it with PL/SQL loop to actually run kill statements:
select ses.USERNAME,
substr(MACHINE,1,10) as MACHINE,
substr(module,1,25) as module,
status,
'alter system kill session '''||SID||','||ses.SERIAL#||''';' as kill
from v$session ses LEFT OUTER JOIN v$process p ON (ses.paddr=p.addr)
where schemaname <> 'SYS'
and not exists
(select 1
from DBA_ROLE_PRIVS
where GRANTED_ROLE='DBA'
and schemaname=grantee)
and machine!='yourlocalhostname'
order by LAST_CALL_ET desc;
If Oracle is running in Unix /Linux then we can grep for all client connections and kill it
grep all oracle client process:
ps -ef | grep LOCAL=NO | grep -v grep | awk '{print $2}' | wc -l
Kill all oracle client process :
kill -9 ps -ef | grep LOCAL=NO | grep -v grep | awk '{print $2}'
Related
I'm trying to get the Hostname, Terminal of logged user in Oracle APEX.
Normally when using database is easy.
e.g.
SELECT SYS_CONTEXT('USERENV','TERMINAL') FROM DUAL;
I have APEX running through tomcat 9.0 on linux server.
When I try it on APEX I get "unknown" value. When I try to get hostname
SELECT SYS_CONTEXT('USERENV','host') FROM DUAL;
I get the name of server that apex/ords/tomcat is running. I need to get the name of terminal of logged user.
Have you tried:
begin
if( owa_util.get_cgi_env('X-Forwarded-For') is not null) then
htp.p('Client address is: ' || owa_util.get_cgi_env('X-Forwarded-For'));
else
htp.p('Remote address is: ' || owa_util.get_cgi_env('REMOTE_ADDR'));
end if;
end;
from
https://community.oracle.com/thread/3994246?start=0&tstart=0
I have lot of databases where schema name is the same as $ORACLE_SID. I would like when i log in to sqlplus something like:
alter session set current_schema=$ORACLE_SID
is executed. Everything what I've tried didn't work.
Try to put such a code into:
login.sql (locally in where you executed sqlplus)
or glogin.sql ($ORACLE_HOME\sqlplus\admin)
declare
l_gln varchar2(30);
begin
select instance_name into l_gln from v$instance;
execute immediate 'alter session set current_schema = ' || l_gln;
end;
/
I have a simple script in bash that just return the count of a given table
The trow command through bash its like that
user>bash Bash_Script.bsh -T MyTableTthatAlreadyExists
After the conections parameters it just do that:
SQLSTRING="SELECT COUNT(*) FROM $SYBTAB;"
BATCH_ARGS=`sqlplus -S /nolog <<SQL | tail -1
connect $ORCL_USR/$ORCL_PWD#$ORCL_TNS;
alter session set nls_date_format='YYYYMMDD';
set pagesize 0 long 4096 linesize 32767 feed off head off;
$SQLSTRING
quit;
SQL`
echo "$BATCH_ARGS"
And it works. Yest it works, it returns the nummer of rows of my table.
The problem come when I create a new table MyNewTable
- The table exists in Oracle
so when I do in SQL Developer
select count(*) from MyNewTable;
return the correct nummer.
But when I throw again the unix command. It doesnt work, it doesnt return anything
user>bash Bash_Script.bsh -T MyNewTable --> return nothing
I wonder myself what I m missing, wat I m not taking account.
I thounk about Grant privileges but they both haven the same.
can anyone here help me ?
Thanks in advance, Enrique
Your script is only getting the last line of output from SQL*Plus
BATCH_ARGS=`sqlplus -S /nolog <<SQL | tail -1
If you remove the tail part:
BATCH_ARGS=`sqlplus -S /nolog <<SQL
then you'll see what is actually happening. With a table that exists, with that modification I see:
user>bash Bash_Script.bsh -T MyTableTthatAlreadyExists
Session altered.
1815
and with a table that does not exist I see:
user>bash Bash_Script.bsh -T MyNewTable
Session altered.
SELECT COUNT(*) FROM t43
*
ERROR at line 1:
ORA-00942: table or view does not exist
It seems you are seeing ORA-01031: insufficient privileges, so the user you are connecting as needs to have select privileges granted for the new table.
As you only want the actual count, if you swap the order of the alter and set clauses the Session altered. message will also be suppressed as feedback will be switched off by then:
BATCH_ARGS=`sqlplus -S /nolog <<SQL
connect $ORCL_USR/$ORCL_PWD#$ORCL_TNS;
set pagesize 0 long 4096 linesize 32767 feed off head off;
alter session set nls_date_format='YYYYMMDD';
$SQLSTRING
quit;
SQL`
and you'd then see, for an existing table, just:
user>bash Bash_Script.bsh -T MyTableTthatAlreadyExists
1815
making the tail unnecessary anyway.
I have created a script that creates Oracle users and grants them roles. I am unable to find a way to ignore the "user exists" error:
ORA-01920: user name '' conflicts with another user or role name.
I understand that when the script is ran, it is possible that the user already exists, but I want to ignore any returned errors. Is this possible?
My Oracle code:
CREATE USER "John" PROFILE "DEFAULT" IDENTIFIED BY "temppassword" ACCOUNT UNLOCK;
Edit:
This question is not asking how to create a user if it doesn't exist. This question is asking how to ignore "the user exists" error. According to a previously asked question, the top answer stated
In general, Oracle scripts simply execute the CREATE statement, and if
the object already exist, you'll get an error indicating that, which
you can ignore. This is whaat all the standard Oracle deployment
scripts do.
It isn't clear how you're running your script, but assuming its via SQL*Plus you can modify the behaviour when an error is encountered with the whenever sqlerror command.
If your script is setting that to exit at the moment, or you're picking that up from a startup script (login.sql, glogin.sql) you can change it back, or modify it temporarily:
...
-- do not stop on error
WHENEVER SQLERROR CONTINUE;
CREATE USER "John" PROFILE "DEFAULT" IDENTIFIED BY "temppassword" ACCOUNT UNLOCK;
-- to stop when later errors are encountered
WHENEVER SQLERROR EXIT FAILURE;
ALTER USER ...
You'll still see the ORA-01920 in the output but it will continue on to execute the next statement. This pattern is also useful for a protective drop of a schema object before attempting to create it.
Why can't you find if the user exists first?
SELECT COUNT(*)
INTO V_count
from ALL_USERS
where username = 'YourUserName'
IF v_count = 0 THEN
--create the user
--execute the grants
ELSE
---log that the user already exists
END IF;
SET SERVEROUTPUT ON;
DECLARE
TYPE t_list IS TABLE OF VARCHAR2 (30);
l_list t_list := t_list ('X0', 'X1', 'X2');
e_user_already_exists EXCEPTION;
PRAGMA EXCEPTION_INIT (e_user_already_exists, -1920);
BEGIN
FOR l_iterator IN 1 .. l_list.COUNT LOOP
DBMS_OUTPUT.PUT_LINE ('Creating user ' || l_list (l_iterator));
BEGIN
EXECUTE IMMEDIATE 'CREATE USER "' || l_list (l_iterator) || '" PROFILE DEFAULT IDENTIFIED BY "WELCOME" ACCOUNT UNLOCK';
EXECUTE IMMEDIATE 'GRANT SOME_APPLICATION_ROLE TO ' || l_list (l_iterator);
EXCEPTION
WHEN e_user_already_exists THEN
DBMS_OUTPUT.PUT_LINE ('User exists, ignored');
WHEN OTHERS THEN
RAISE;
END;
END LOOP;
END;
/
Friends...
DB: Oracle11gR2
OS: Linux
I have created package with couple of procedure, procedure executes alter table move... , index rebuild command on database.
I'm doing below
Run ksh shell script -> execute procedure
Procedure runs alter table, rebuild index commands on database
Procedure completes
Shell script ends.
I can generate logfile for the shell script but whatever gets executed by procedure doesn't get recorded inside shell script logfile. I understood since db session created by procedure it won't record anything in shell logfile.
So how can I
Record everything in logfile which is executed by both procedures in the same package?
Also trying to put current datetime within procedure dmbs_out.put_line command?
Is it possible to run both procedure after connecting database once instead of 2 time connecting database and executing procedure?
There might be table/table partition move syntax error but I'm only trying to trap when table move started and when finished with datetime so to identify total time taken.
*** ksh script
#!/bin/ksh
...
...
...
$LOG_FILE = move_tbs.log
echo -e "set serveroutput on\n exec move_tbs.moveTable;"|$ORACLE_HOME/bin/sqlplus/#db_alias | head -l
echo -e "set serveroutput on\n exec move_tbs.moveTablePart;"|$ORACLE_HOME/bin/sqlplus/#db_alias | head -l
DB Package / Procedure
*** Procedure
create or replace package move_all
procedure moveTable
dbms_output.put_line("CURRENT TIME" 'alter table '|| owner || '.' || table_name || 'move');
Execute immediate 'alter table '|| owner || '.' || table_name || 'move';
dbms_output.put_line("COMPLETED TIME" : CURRENT_TIME);
end moveTable;
-------------------------------------------
procedure moveTablePart
dbms_output.put_line("CURRENT TIME" 'alter table '|| owner || '.' || table_name || 'move');
Execute immediate 'alter table '|| owner || '.' || table_name || 'move partition';
dbms_output.put_line("COMPLETED TIME" : CURRENT_TIME);
end moveTablePart;
end move_all
/
You could just put both exec commands in your echo construct. But you can use a 'heredoc' to simplify running both together, and it's a easier to read and maintain too. Something like:
LOG_TBS_MOVE=move_tbs.log
(
$ORACLE_HOME/bin/sqlplus -s -l user/passwd#db_alias <<!EOF
set serveroutput on
exec move_tbs.moveTable;
exec move_tbs.moveTablePart;
exit
!EOF
) > $LOG_TBS_MOVE
The herdoc start and end markers in this example !EOF - have to match exactly. They can be anything you like as long as there's no chance of anything inside the heredoc accidentally ending it. And the end marker has to be at the start of a line, it can't be indented.
The parentheses around the SQL*Plus and heredoc can enclose multiole commands and all output from within them goes into the log. They aren't really necessary here as there is only one command inside but it's a fairly clear way of doing the redirection, I think.
I'm only putting stdout into the $LOG_TBS_MOVE file; anything on stderr (which will not include any SQL errors) will still go to screen or to your main log if you redirect stderr for that.
To show the time in your output, don't enclose the current_time part in quotes, use string concatenation, and use the right function:
dbms_output.put_line(to_char(sysdate, 'HH24:MI:SS') ||
'alter table '|| owner || '.' || table_name || 'move');
dbms_output.put_line('COMPLETED TIME: ' || to_char(sysdate, 'HH24:MI:SS'));
Or you could display the time from the shell instead, within the parentheses; that would also then go into the same log file.
You haven't shown a username or password in your SQL*Plus calls; you probably just hid them, but if you are connecting as SYS via /, you really shouldn't be creating objects in that schema. Create a new schema and work in that.