Wednesday, February 20, 2013

ORA-00054: resource busy and acquire with NOWAIT specified


A common error we face on day to day life. Happens when someone tries to modify a table which is already locked by other user.

Now there are couple of ways to get rid of it.

   1. Check to see which user is locking the object and then kill the session.

select a.sid, a.serial#
from v$session a, v$locked_object b, dba_objects c
where b.object_id = c.object_id
and a.sid = b.session_id
and OBJECT_NAME='EMP';

alter system kill session 'sid,serial#'; 

2. In 11g we can set ddl_lock_timeout to allow DDL to wait for the object becomes available. We can specify how long we’d want to wait for executing DDL.
 
SQL> alter session set ddl_lock_timeout = 600;
Session altered.
SQL> alter table emp add (gender varchar2(10));
Table altered.


  3. If you don’t want to hamper other users, then either try executing DDL at off-peak hours or
  4. Wait for few minutes until the other user releases the lock on same object.
  5. In 11g you can put a table in readonly mode to ensure no one locking it and then execute your command.

SQL> alter table emp read only;
Session altered.
 SQL> alter table emp add (gender varchar2(10));
Table altered.

ORA-00018 maximum number of sessions exceeded


ORA-00018 maximum number of sessions exceeded
Cause: All session state objects are in use.
Action: Increase the value of the SESSIONS initialization parameter.
 
ORA-00018 comes under "Oracle Database Server Messages". These messages are generated by the Oracle database server when running any Oracle program.

How to increase SESSION initialization parameter:
1. Login as sysdba
 sqlplus / as sysdba
 
2. Check Current Setting of Parameters
 sql> show parameter sessions
 sql> show parameter processes
 sql> show parameter transactions
 
3. If you are planning to increase "sessions" parameter you should also plan to increase "processes and "transactions" parameters.
 
A basic formula for determining  these parameter values is as follows:
 
  processes=x
  sessions=x*1.1+5
  transactions=sessions*1.1
  
4. These paramters can't be modified in memory. You have to modify the spfile only (scope=spfile) and bounce the instance.
 
 sql> alter system set processes=500 scope=spfile;
 sql> alter system set sessions=555 scope=spfile;
 sql> alter system set transactions=610 scope=spfile;
 sql> shutdown abort
 sql> startup 
 

How to SCRUB/MASK data using expdp (REMAP_DATA feature)


This is a common requirement for DBA to export data from production for various purposes. In a restricted & compliant environment it’s a must to mask / scrub particular data while exporting from production.
Here’s a simple demonstration. I’ve got the hint from metalink.

  1. Create a package to mask data

Note: The package needs to be created under the schema which would be used to connect to datapump utility. I’ve used SYSTEM user for this case.

as
  function toggle_case(p_value varchar2) return varchar2;
end;
/

create or replace package body datapump_remap_test
as
  function toggle_case(p_value varchar2) return varchar2 is
  begin
    return translate(p_value,    
      'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890!@#$%^&*()_+-=\/ ',
        'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
end;
end;
/

  2. Datapump export with REMAP_DATA parameter:

We’d be using the created package to scrub data for particular table columns. My package would basically replace all mentioned column data into ‘xxxxx’
For this example, I’ve chosen to scrub HR.FIRST_NAME & SALES. The export dump would export the FNADVI schema as well as the the table mentioned with scrubbed column.

expdp system dumpfile=fnadvi.dmp directory=dump logfile=fnadvi.dmp.log schemas=fnadvi remap_data=fnadvi.HR.first_name:system.datapump_remap_test.toggle_case remap_data=fnadvi.SALES.address:system.datapump_remap_test.toggle_case

  3. Import the schema
Now you the import can be done anywhere with scrubbed data.

Thursday, February 14, 2013

WRAPPING Oracle procedure/function


In order to hide any procedure/function we can use oracle wrap utility. This would hide the code from user, but still the procedure can execute.

Here is the demonstration.

1   1. Create an sql file on database OS.

[oracle@lab ~]$ cat wrapping_proc.sql
CREATE OR REPLACE PROCEDURE wrapping_proc
IS
BEGIN
   DBMS_OUTPUT.PUT_LINE('WRAP TESTING');
 END;
/

    2. WRAP the sql file, this would create a wrapped file with .plb extension. Try the below command.

[oracle@lab ~]$ wrap iname=wrapping_proc.sql
PL/SQL Wrapper: Release 11.2.0.2.0- 64bit Production on Thu Feb 14 15:33:26 2013
Copyright (c) 1993, 2009, Oracle.  All rights reserved.
Processing wrapping_proc.sql to wrapping_proc.plb

3. Now copy the content of .plb file, and execute it after logging into the database.

[oracle@lab~]$ cat wrapping_proc.plb
CREATE OR REPLACE PROCEDURE wrapping_proc wrapped
a000000
1
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
7
50 92
AjmXfCjRF6msrZKufRFrtUPnC5gwg5nnm7+fMr2ywFwWlvJWFoVHDNCWFpeui5t0i8DAMv7S
hglpabhSm7JK/iiyveeysx0GMCyuJOqygaXKxqYCL7GPL64kvzIu9tFE6iQf9jmms29vnw==
/

4. Logging into the database to execute it.

[oracle@lab~]$ sqlplus scott/tiger
SQL> CREATE OR REPLACE PROCEDURE wrapping_proc wrapped
  2  a000000
  3  1
abcd
  4    5  abcd
abcd
  6    7  abcd
abcd
  8    9  abcd
 10  abcd
 11  abcd
 12  abcd
abcd
 13   14  abcd
 15  abcd
 16  abcd
 17  abcd
 18  abcd
 19  7
 20  50 92
 21  AjmXfCjRF6msrZKufRFrtUPnC5gwg5nnm7+fMr2ywFwWlvJWFoVHDNCWFpeui5t0i8DAMv7S
 22  hglpabhSm7JK/iiyveeysx0GMCyuJOqygaXKxqYCL7GPL64kvzIu9tFE6iQf9jmms29vnw==
 23
 24
 25  /

Procedure created.

   5.  Try executing and it works!

SQL> exec wrapping_proc;

PL/SQL procedure successfully completed.

SQL> drop procedure wrapping_proc;

Procedure dropped.


Now the interesting part is Even though Oracle claims the wrapped code can't be unwrapped. But it does!!!
There are couple of weblink where you can easily unwrap it. So the point of wrapping has become useless :(

The following link is one of them.
http://www.codecrete.net/UnwrapIt/

ORA-39083/ORA-02304 during impdp


Was facing the following errors while impdp. Reason for this error is OID should be unique in each DB. In this case, OID in the impdp was using old schema value thus failing.

ORA-39083: Object type TYPE failed to create with error:
ORA-02304: invalid object identifier literal

Solution is to use transform=OID:n on my impdp parameter.

Example :
impdp username DIRECTORY=DUMP transform=OID:n DUMPFILE=schema.dmp

Now all good!

Tuesday, February 12, 2013

Moving LOBS along with Tables


Moving a regular table to a different tablespace is straight forward.

Alter table move tablespace  ;

And then rebuild the indexes as it becomes invalid. But what if the table has LOB segments? Similar to INDEX, the LOB doesn’t moves where the table just relocated.

You can run the followings to see where it’s located. And take decision where do you want the LOB to move.

select owner, table_name, column_name,tablespace_name from dba_lobs where segment_name in (select segment_name from dba_segments where tablespace_name = 'SCOTT_DATA' );
Example:

select owner, table_name, column_name,tablespace_name from dba_lobs where segment_name in (select segment_name from dba_segments where tablespace_name like '%DATA' )
and table_name like '%LOG%'
and owner like 'SL%';

If you want to move only lob segment to a new tablespace then your command will be,

ALTER TABLE table_name MOVE LOB(lob_columnname) STORE AS (TABLESPACE new_tablespace_name);

We can also move table and LOB altogether with the below command:

ALTER TABLE table_name MOVE
TABLESPACE new_tablespace

LOB (lobcol1,lobcol2) STORE AS
(TABLESPACE new_tablespace);

Thursday, January 31, 2013

"ORA-12502: TNS:listener received no CONNECT_DATA" when connecting to a SCAN address


This is a client side error. Nothing to do with the database. Usually, if the hostname used in tnsnames.ora are not resolvable by the client then the subject lined error appears.

For my case, I was facing this error for a 2 node RAC cluster 11gR2 database. We are using SCAN address in the tnsnames.ora. Even though the client can resolve scan still it's failing. 
Why?
Because, not only the SCAN but all server in the cluster needs to be resolvable by application clients. This includes the host VIPs and real IP of all the servers in the RAC configuration.

Look at the demonstration of this error:
 I can ping the DB alias from client pc.

#tnsping DB1

TNS Ping Utility for Linux: Version 11.2.0.1.0 - Production on 31-JAN-2013 14:13:09
Copyright (c) 1997, 2009, Oracle.  All rights reserved.
Used parameter files:
/opt/oracle/product/11.2.0/client_1/network/admin/sqlnet.ora

Used TNSNAMES adapter to resolve the alias
Attempting to contact (DESCRIPTION = (ADDRESS=(PROTOCOL=TCP)(HOST=db1-scan)(PORT=1521)) (CONNECT_DATA = (SERVER=dedicated) (SERVICE_NAME= db1.mycompany.com)))
OK (0 msec)

But, Can't connect to the database using SQLPLUS.

sqlplus ***/****@db1

SQL*Plus: Release 11.2.0.1.0 Production on Thu Jan 31 14:13:35 2013
Copyright (c) 1982, 2009, Oracle.  All rights reserved.
ERROR:
ORA-12502: TNS:listener received no CONNECT_DATA from client


It's because, the client firewall rule is blocking it from communicating either.
VIP/Real IPS of all the servers associated with RAC configuration.

The problem was fixed after fixing firewall in accessing VIP.



Tuesday, January 29, 2013

ORA-12162 TNS:net service name is incorrectly specified

After creating a new environment and database. I was facing this error. Even trying to logging in sys as sysdba was failing.

[oracle@lab ~]$ sqlplus / as sysdba
SQL*Plus: Release 11.2.0.3.0 Production on Tue Jan 29 15:15:46 2013
Copyright (c) 1982, 2011, Oracle.  All rights reserved.
ERROR:
ORA-12162: TNS:net service name is incorrectly specified

Looking into the error doesn't exactly tell what the issue is. This was actually environmental variable related issue. Nothing to do with tns, listener or even with the database.

I'm running oracle on linux. So needs to set ORACLE_HOME and ORACLE_SID variable correctly.

ORACLE_HOME=/u01/app/oracle/product/11.2.0/db_1; export ORACLE_HOME
ORACLE_SID=labdb; export ORACLE_SID

That's it! Now I'm able to login

[oracle@lab~]$ sqlplus / as sysdba
Connected to:
Oracle Database 11g Release 11.2.0.3.0 - 64bit Production


Wednesday, July 04, 2012

Ora-12012: Error On Auto Execute Of Job "Oracle_ocm"."Mgmt_config_job_2_1


OCM job was failing with below error at alert log:
 ORA-12012: error on auto execute of job "ORACLE_OCM"."MGMT_CONFIG_JOB_2_1"
ORA-29280: invalid directory path
ORA-06512: at "ORACLE_OCM.MGMT_DB_LL_METRICS", line 2436
ORA-06512: at line 1


This messages happen because of the OCM collection database job is unable to access the directory location where the OCM data is written .
If you do not use OCM delete the OCM configuration from the database:

Log in to your database as user SYS and drop-cascade user ORACLE_OCM:
SQL> DROP USER ORACLE_OCM CASCADE;

But if OCM is in use to upload collection to My Oracle Support then it needs reinstrumenting the database.

1. export ORACLE_HOME=
    export ORACLE_SID=

2.  Remove the OCM configuration in the database:

     cd $ORACLE_HOME/ccr/bin
     ./configCCR -r

3. Configure the OCM configuration in the database:

    ./configCCR -a

4.  Instrument the Database:

     cd /ccr/admin/scripts
     ./installCCRSQL.sh collectconfig -s -r SYS

5.  Run a manual collection:

    cd $ORACLE_HOME/ccr/bin
    ./emCCR collect


Friday, June 22, 2012

TNS-01189: The listener could not authenticate the user

I was working on restoring database to a new VM lab environment. So the TNS, Listener , PFILe everything was copied over as usual as I'll be doing RMAN restore. So the restoration went fine, but interestingly listener didn't like my user to run it. Error was a bit confusing to me. Here is what I got.

[oracle@lab]$ lsnrctl status
LSNRCTL for Linux: Version 11.2.0.2.0 - Production on 22-JUN-2012 09:55:32
Copyright (c) 1991, 2010, Oracle.  All rights reserved.
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=production.com)(PORT=1521)))
TNS-01189: The listener could not authenticate the user

I was so stupid that I was only looking into the error. Then I suddenly looked into the HOST name. It was picking up my source database as hostname; as I just copied the listener.ora file but didn't modified!

Solution is simple. Just change the listener HOST entry according to the server you are restoring the DB.

vi $ORACLE_HOME/network/admin/listener.ora

# listener.ora Network Configuration File: /u01/app/oracle/product/11.1.0/db_1/network/admin/listener.ora
# Generated by Oracle configuration tools.

LISTENER =
  (DESCRIPTION_LIST =
    (DESCRIPTION =
      (ADDRESS = (PROTOCOL = TCP)(HOST = lab)(PORT = 1521))
      (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
    )
  )

Tuesday, June 12, 2012

Oracle Number to Word conversion




select decode( sign( &num ), -1, 'Negative ', 0, 'Zero', NULL ) ||
       decode( sign( abs(&num) ), +1, to_char( to_date( abs(&num),'J'),'Jsp') )
from dual
/


First one has a limitation of number of digits. Below one is good in terms of number of digits.


Set Serveroutput On 1000000
Declare
  V_Input NUMBER := &TESTED;
  Function Numbertowords(P_Number In Out Number) Return Varchar2 Is
    V_Words Varchar2(32767) := ' ';
    V_Temp Number;   
    Type Unitsmap Is Table Of Varchar2(250) Index By Binary_Integer;
    Type Tensmap Is Table Of Varchar2(250) Index By Binary_Integer;   
    V_Unitsmap Unitsmap ;
    V_Tensmap Tensmap   ;
  Begin
    V_Unitsmap(0) := 'Zero';
    V_Unitsmap(1) := 'One';
    V_Unitsmap(2) := 'Two';
    V_Unitsmap(3) := 'Three';
    V_Unitsmap(4) := 'Four';
    V_Unitsmap(5) := 'Five';
    V_Unitsmap(6) := 'Six';
    V_Unitsmap(7) := 'Seven';
    V_Unitsmap(8) := 'Eight';
    V_Unitsmap(9) := 'Nine';
    V_Unitsmap(10) := 'Ten';
    V_Unitsmap(11) := 'Eleven';
    V_Unitsmap(12) := 'Twelve';
    V_Unitsmap(13) := 'Thirteen';
    V_Unitsmap(14) := 'Fourteen';
    V_Unitsmap(15) := 'Fifteen';
    V_Unitsmap(16) := 'Sixteen';
    V_Unitsmap(17) := 'Seventeen';
    V_Unitsmap(18) := 'Eighteen';
    V_Unitsmap(19) := 'Nineteen';
    V_Tensmap(2)  := 'Twenty';
    V_Tensmap(3)  := 'Thirty';
    V_Tensmap(4)  := 'Forty';
    V_Tensmap(5)  := 'Fifty';
    V_Tensmap(6)  := 'Sixty';
    V_Tensmap(7)  := 'Seventy';
    V_Tensmap(8)  := 'Eighty';
    V_Tensmap(9)  := 'Ninety';
    If (P_Number = 0) Then
      Return 'Zero';
    End If;
    If (P_Number < 0) Then
      V_Temp := Abs(P_Number);     
      Return 'Minus ' || Numbertowords(V_Temp);
    End If;
    V_Temp := TRUNC(P_Number / 1000000);
    If ( V_Temp > 0) Then
      V_Words := V_WORDS || Numbertowords(V_Temp) || ' Million';
      P_Number := Mod(P_Number,1000000);
    End If;
    V_Temp := TRUNC(P_Number / 1000);
    If ( V_Temp > 0)Then
      V_Words := V_Words || Numbertowords(V_Temp) || ' Thousand';
      P_Number := Mod(P_Number,1000);
    End If;
    V_Temp := Trunc(P_Number / 100);
    If ( V_Temp > 0) Then
      V_Words := V_Words ||  Numbertowords(V_Temp) || ' Hundred ';
      P_Number := Mod(P_Number,100);
    End If;
    V_Temp := P_Number;
    If (V_Temp > 0) Then
      If (V_Words != ' ') Then
        V_Words := V_Words || 'And ';
       End If;
      If (V_Temp < 20) Then
        V_Words := V_Words || V_Unitsmap(V_Temp);
        Return V_Words;
      Else
       V_Temp := TRUNC(P_Number/ 10);
        V_Words := V_Words || V_Tensmap(V_Temp);
        If ((Mod(P_Number ,10)) > 0) Then
          V_Words :=V_Words|| '-' ||V_Unitsmap(Mod(P_Number,10));
        End If;
      End If;       
    End If;
    Return V_Words;
  End;
Begin   
  Dbms_Output.Put_Line(&TESTED||' ='||Numbertowords(V_Input));
End;