Monday, December 29, 2014

How to move LOB segments in a sub-partitioned table to a new tablespace


Find the sub-partitions that you would like to relocate:

SELECT TABLE_OWNER,TABLE_NAME,COLUMN_NAME,LOB_NAME,SUBPARTITION_NAME,LOB_PARTITION_NAME,SECUREFILE,TABLESPACE_NAME
FROM DBA_LOB_SUBPARTITIONS 
WHERE TABLE_OWNER = 'SCOTT'
AND TABLESPACE_NAME = 'USERS';

TABLE_OWNER TABLE_NAME COLUMN_NAME LOB_NAME SUBPARTITION_NAME LOB_PARTITION_NAME SECUREFILE TABLESPACE_NAME
SCOTT TMP_POSK_LEVERANSER TOTALER SYS_LOB0000093760C00010$$ P_2013_P_AMELDING SYS_LOB_P441 NO USERS
SCOTT TMP_POSK_LEVERANSER TOTALER SYS_LOB0000093760C00010$$ P_2013_P_DEFAULT SYS_LOB_P441 NO USERS
SCOTT TMP_POSK_LEVERANSER XML_INNHOLD SYS_LOB0000093760C00020$$ P_2013_P_AMELDING SYS_LOB_P447 NO USERS
SCOTT TMP_POSK_LEVERANSER XML_INNHOLD SYS_LOB0000093760C00020$$ P_2013_P_DEFAULT SYS_LOB_P447 NO USERS
SCOTT TMP_POSK_LEVERANSER OPPSUMMERING SYS_LOB0000093760C00021$$ P_2013_P_AMELDING SYS_LOB_P453 NO USERS
SCOTT TMP_POSK_LEVERANSER OPPSUMMERING SYS_LOB0000093760C00021$$ P_2013_P_DEFAULT SYS_LOB_P453 NO USERS

See this post for a more advanced variant that will also show the size of each LOB subpartition

Some examples of correct syntax to move such LOB segments are given below:

-- move a basicfile LOB
alter table SCOTT.TMP_POSK_LEVERANSER move subpartition P_2013_P_AMELDING lob (TOTALER) store as basicfile (tablespace DATA1);

-- move a securefile LOB. Allow for DML and make sure global indexes are not rendered unusable
alter table SCOTT.TMP_POSK_LEVERANSER 
move subpartition P_2013_P_DEFAULT 
lob (OPPSUMMERING) store as securefile (tablespace DATA1) ONLINE UPDATE GLOBAL INDEXES;

-- move a securefile LOB and compress it
alter table SCOTT.TMP_POSK_LEVERANSER 
move subpartition P_2013_P_MELDING 
lob (PDFATTACHMENT) store as securefile (tablespace LOB_DATA COMPRESS MEDIUM);'


Generate the DDLs:
SELECT 'alter table ' || TABLE_OWNER || '.' || TABLE_NAME || ' move subpartition ' || SUBPARTITION_NAME || ' lob (' || COLUMN_NAME || ') store as securefile|basicfile(tablespace DATA1 compress LOW|MEDIUM|HIGH) ONLINE UPDATE GLOBAL INDEXES;' 
FROM DBA_LOB_SUBPARTITIONS 
WHERE TABLE_OWNER = 'SCOTT'
AND TABLESPACE_NAME = 'USERS'
-- to limit your script to certain subpartitions only, uncomment the line below
-- AND SUBPARTITION_NAME='MY_SUBPART_NAME'
;

I have used this script successfully in the past, which generates a log file and sets MODULE and ACTION etc in its session:
accept table_owner prompt 'Table owner: '
accept table_name prompt 'Table name: '
accept new_tabspc prompt 'New tablespace: '
accept old_tabspc prompt 'Old tablespace: '

set lines 300
set heading off
set feedback off
set verify off
set echo off
set pages 0
set trimspool on
spool exec_move_lob_&&table_owner..&&table_name..sql
select 'alter session set nls_language=''american'';' from dual;
select 'alter session force parallel ddl;' from dual;
select 'set timing on' from dual;
select 'set lines 200' from dual;
select 'set trimspool on' from dual;
select 'spool exec_move_lob_&&table_owner..&&table_name..log' from dual;
select 'exec DBMS_APPLICATION_INFO.SET_MODULE(module_name=>''Move'', action_name=>''MoveLOB_&&table_name'');' from dual;
select 'exec DBMS_APPLICATION_INFO.SET_CLIENT_INFO (client_info=>''MoveLOB_&&table_name'');' from dual;
select 'exec DBMS_SESSION.SET_IDENTIFIER (client_id=>''MoveLOB_&&table_name''); ' from dual;


SELECT 'alter table ' || ts.TABLE_OWNER || '.' || ts.TABLE_NAME || ' move subpartition ' || lsp.subpartition_name || ' lob (' || lsp.column_name || ') store as securefile (tablespace &&new_tabspc COMPRESS MEDIUM) ONLINE UPDATE GLOBAL INDEXES;'
FROM dba_segments s JOIN dba_lob_subpartitions lsp
ON (s.partition_name = lsp.lob_subpartition_name)
   JOIN DBA_TAB_SUBPARTITIONS ts
        ON (TS.SUBPARTITION_NAME = lsp.SUBPARTITION_NAME)
WHERE lsp.table_name    = '&&table_name'
AND   ts.table_name     = '&&table_name'
-- To limit the output to a specific tablespace, uncomment the line below
--AND   s.tablespace_name = '&&old_tabspc'
AND   ts.table_owner    = '&&table_owner'
-- To limit output to specific table subpartitions only, uncomment the following row
--AND   lsp.subpartition_name like 'SYS_SUBP186786%'
AND s.segment_name IN ( SELECT lpt.lob_name
                        FROM dba_lob_partitions lpt
                        WHERE lpt.table_name IN ( '&&table_name' ) )
GROUP BY ts.table_owner,ts.table_name,s.SEGMENT_NAME,s.SEGMENT_TYPE,s.SEGMENT_SUBTYPE,s.PARTITION_NAME,lsp.COMPRESSION,lsp.subpartition_name, lsp.column_name,ts.num_rows,lsp.tablespace_name
-- To limit output to lob subpartitions with a specific size, uncomment the restriction above and change the operator to suit your needs ( <, >, =, =>, <= or use BETWEEN x AND y)
--HAVING ROUND(sum(s.bytes)/1024/1024/1024) between 1 and 10
ORDER BY lsp.subpartition_name DESC;

select 'exit' from dual;
exit

How to move LOB segments in a partitioned table to a new tablespace


During an attempt to move a partition that contained a LOB segment from one tablespace to another, I hit the infamous ORA-14511 "Cannot perform operation on a partitioned object" more than once. Neither is the Oracle documentation very clear in the matter.

Here is how I relocated LOB segments in a partitioned table from tablespace USERS to the correct tablespace DATA1.

The original DDL for the was as follows:
CREATE TABLE SCOTT.MYTABLE
(
  BQID                    VARCHAR2(36 BYTE)     NOT NULL,
  KLM_ID                  VARCHAR2(36 BYTE),
  PANUM                   NUMBER(18),
  IAA                     NUMBER(16),
  OPPGVTYP                VARCHAR2(50 BYTE),
  BSTAT                   VARCHAR2(60 BYTE),
  LEVREF                  VARCHAR2(50 BYTE)     NOT NULL,
  KSYSTEM                 VARCHAR2(255 BYTE),
  ANT_OPPG                NUMBER(18),
  TOTALER                 CLOB,
  OPPR                    TIMESTAMP(6)          NOT NULL,
  OPP_KI                  VARCHAR2(30 BYTE)     NOT NULL,
  SIST_ENDRET             TIMESTAMP(6)          NOT NULL,
  XML_INNHOLD             CLOB,
  OPPSUMMERING            CLOB,
  ERSTATTERREFERANSE      VARCHAR2(150 CHAR),
  LEVERANSETIDSPUNKT      TIMESTAMP(6),
  LEVERANSETYPE           VARCHAR2(150 BYTE),
  TMP_MD5_OPPSUMMERING    VARCHAR2(32 BYTE)
)
LOB (TOTALER) STORE AS (
  TABLESPACE  DATA1
 )
LOB (XML_INNHOLD) STORE AS (
  TABLESPACE  DATA1
 )
LOB (OPPSUMMERING) STORE AS (
  TABLESPACE  DATA1
 )
TABLESPACE DATA1
PARTITION BY LIST (TASKTYPE)
(  
  PARTITION P_MESSAGE VALUES ('EZAP')
    TABLESPACE DATA1
    LOB (TOTALER) STORE AS (
      TABLESPACE  USERS
    )
    LOB (XML_INNHOLD) STORE AS (
      TABLESPACE  USERS
    )
    LOB (OPPSUMMERING) STORE AS (
      TABLESPACE  USERS
    )
    ,  
  PARTITION P_DEFAULT VALUES (DEFAULT)
    TABLESPACE DATA1
    LOB (TOTALER) STORE AS (
      TABLESPACE  USERS
    )
    LOB (XML_INNHOLD) STORE AS (
      TABLESPACE  USERS
    )
    LOB (OPPSUMMERING) STORE AS (
      TABLESPACE  USERS
    )
)
;

A query against DBA_LOB_PARTITIONS shows that they are indeed placed in tablespace USERS:
SELECT TABLE_OWNER,TABLE_NAME,COLUMN_NAME,LOB_NAME,PARTITION_NAME,LOB_PARTITION_NAME,SECUREFILE,TABLESPACE_NAME
FROM DBA_LOB_PARTITIONS 
WHERE TABLE_OWNER = 'SCOTT' 
AND TABLESPACE_NAME = 'USERS'
AND PARTITION_NAME = 'P_AMELDING';

TABLE_OWNER TABLE_NAME COLUMN_NAME LOB_NAME PARTITION_NAME LOB_PARTITION_NAME SECUREFILE TABLESPACE_NAME
SCOTT MYTABLE TOTALER SYS_LOB0000093789C00010$$ P_AMELDING SYS_LOB_P701 NO USERS
SCOTT MYTABLE XML_INNHOLD SYS_LOB0000093789C00020$$ P_AMELDING SYS_LOB_P703 NO USERS
SCOTT MYTABLE OPPSUMMERING SYS_LOB0000093789C00021$$ P_AMELDING SYS_LOB_P705 NO USERS

The correct syntax to move these LOB segments is:
ALTER TABLE SCOTT.MYTABLE
MOVE PARTITION P_AMELDING
LOB (TOTALER) STORE AS BASICFILE (TABLESPACE DATA1);

ALTER TABLE SCOTT.MYTABLE
MOVE PARTITION P_AMELDING
LOB (OPPSUMMERING) STORE AS BASICFILE (TABLESPACE DATA1);

ALTER TABLE SCOTT.MYTABLE
MOVE PARTITION P_AMELDING
LOB (XML_INNHOLD) STORE AS BASICFILE (TABLESPACE DATA1);

To generate DDL statements:
SELECT 'alter table ' || TABLE_OWNER || '.' || TABLE_NAME || ' move partition ' || partition_name || ' lob (' || COLUMN_NAME || ') store as basicfile (tablespace data1);'
FROM DBA_LOB_PARTITIONS 
WHERE TABLE_OWNER = 'SCOTT' 
AND TABLESPACE_NAME = 'USERS'
AND SECUREFILE='NO';

If the table is also sub-partitioned, you may want to check this post.

Wednesday, December 17, 2014

Why are statements executed by SYS not found in the DB audit trail?


Even if Oracles default auditing is set up, it surprised me that audit information did not appear in the audit trail, for statements that should be covered by default auditing.

Below are my findings.


First, let's check which audit privileges that are set already:

-- DBA_PRIV_AUDIT_OPTS: describes current system privileges being audited across the system and by user.
SELECT * 
FROM DBA_PRIV_AUDIT_OPTS;

USER_NAME PROXY_NAME PRIVILEGE SUCCESS FAILURE
    GRANT ANY PRIVILEGE BY ACCESS BY ACCESS
    ALTER DATABASE BY ACCESS BY ACCESS
    ALTER USER BY ACCESS BY ACCESS
    CREATE USER BY ACCESS BY ACCESS
    CREATE SESSION BY ACCESS BY ACCESS
    ALTER SYSTEM BY ACCESS BY ACCESS

Let's audit CREATE USER by user SYSTEM:

SQL> connect / as sysdba
SQL> AUDIT CREATE USER BY SYSTEM;

Check again that the audit trail that is set
SELECT * 
FROM DBA_PRIV_AUDIT_OPTS;
USER_NAME PROXY_NAME PRIVILEGE SUCCESS FAILURE
    GRANT ANY PRIVILEGE BY ACCESS BY ACCESS
    ALTER DATABASE BY ACCESS BY ACCESS
    ALTER USER BY ACCESS BY ACCESS
SYSTEM   CREATE USER BY ACCESS BY ACCESS
    CREATE SESSION BY ACCESS BY ACCESS
    ALTER SYSTEM BY ACCESS BY ACCESS


Log in as user SYS, and create a user:
SQL> connect sys/****@proddb01 as sysdba
SQL> connected.
SQL> CREATE USER VKAASA IDENTIFIED BY password 
SQL> DEFAULT TABLESPACE USERS
SQL> TEMPORARY TABLESPACE TEMP;

User created.

Log in as user SYSTEM, and create a user:
SQL> connect system/****
SQL> CREATE USER SCOTT IDENTIFIED BY password 
SQL> DEFAULT TABLESPACE USERS
SQL> TEMPORARY TABLESPACE TEMP;

User created.
To find the audit entry, check the DBA_COMMON_AUDIT_TRAIL. This view displays all standard and fine-grained audit trail entries, mandatory and SYS audit records written in XML format.

SELECT AUDIT_TYPE,EXTENDED_TIMESTAMP, DB_USER, OS_USER,USERHOST,OBJECT_NAME,STATEMENT_TYPE,SCN,SQL_TEXT,PRIV_USED
FROM DBA_COMMON_AUDIT_TRAIL 
WHERE PRIV_USED = 'CREATE USER'
AND TO_CHAR(extended_timestamp AT TIME ZONE DBTIMEZONE, 'YYYY-MM-DD HH24:MI:SS TZD') > TO_CHAR((SYSDATE-1),'YYYY-MM-DD HH24:MI:SS');

AUDIT_TYPE EXTENDED_TIMESTAMP DB_USER OS_USER USERHOST OBJECT_NAME STATEMENT_TYPE SCN SQL_TEXT PRIV_USED
Standard Audit 17.12.2014 13:05:06,515954 +01:00 SYSTEM oracle myserver scott CREATE USER
153820329960
create user scott identified by * default tablespace users temporary tablespace temp CREATE USER

The same audit entry can be found in DBA_AUDIT_TRAIL, which displays all standard audit trail entries.

SELECT OS_USERNAME,USERNAME,USERHOST,TIMESTAMP,OBJ_NAME,ACTION_NAME,RETURNCODE,PRIV_USED,SCN,SQL_TEXT
FROM DBA_AUDIT_TRAIL
WHERE PRIV_USED = 'CREATE USER'
AND TO_CHAR(extended_timestamp AT TIME ZONE DBTIMEZONE, 'YYYY-MM-DD HH24:MI:SS TZD') > TO_CHAR((SYSDATE-1),'YYYY-MM-DD HH24:MI:SS');

OS_USERNAME USERNAME USERHOST TIMESTAMP OBJ_NAME ACTION_NAME RETURNCODE PRIV_USED SCN SQL_TEXT
oracle SYSTEM myserver 17.12.2014 13:05:06 scott CREATE USER
0
CREATE USER
153820329960
create user scott identified by * default tablespace users temporary tablespace temp


So what happened to the other user, vkaasa, created by SYS? Shouldn't that leave an entry in the audit trail as well?

- You cannot audit actions by sys the same way. Trying to enable audit for user SYS will throw ORA-00983:
SQL> audit create user by sys;
audit create user by sys
*
ERROR at line 1:
ORA-00983: cannot audit or noaudit SYS user actions

Any user creation by sys, which has the sysdba privilege will not be audited. Donald Burleson at Burleson Consulting puts it this way:

"When a user with SYSDBA privileges connects to the database, the action is expected to be for administrative reasons only, such as shutdown, startup, add a service to the listener, etc. Generally, we would not expect these actions to be audited and therefore not picked up by the auditing mechanism.

However, the user who is connected as SYSDBA is a regular user, just like any other user, but with all powerful do anything privileges. This user could potentially alter the data in a table in any schema. Since the action is not audited, the trace of this data manipulation is hidden. In case of an investigation later, the audit trails will have no record of such manipulations ? a huge security hole"

However, any CREATE USER action executed by sys is recorded in the audit trail on disk:
SQL> show parameter audit_file_dest

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
audit_file_dest                      string      /u01/oracle/admin/proddb01/adump

cd /u01/oracle/admin/proddb01/adump
ls -latr 

-rw-r-----    1 oracle   dba            2754 Dec 17 13:03 proddb01_ora_56099020_20141217130109908038143795.aud
-rw-r-----    1 oracle   dba            1429 Dec 17 13:24 proddb01_ora_56426540_20141217132347629420143795.aud
-rw-r-----    1 oracle   dba           66871 Dec 17 13:27 proddb01_ora_58458244_20141217075116217921143795.aud
drwxrwxr-x    2 oracle   dba           73728 Dec 17 13:33 .
-rw-r-----    1 oracle   dba            2612 Dec 17 13:33 proddb01_ora_57475318_20141217133329412931143795.aud

Open the file proddb01_ora_56426540_20141217132347629420143795.aud:

Wed Dec 17 13:24:37 2014 +01:00
LENGTH : '243'
ACTION :[85] 'create user vkaasa identified by * default tablespace users temporary tablespace temp'
DATABASE USER:[3] 'SYS'
PRIVILEGE :[6] 'SYSDBA'
CLIENT USER:[6] 'myuser'
CLIENT TERMINAL:[7] 'myterminal'
STATUS:[1] '0'
DBID:[10] '3707088731'

How can I check which tables that are being audited in my database?


The experiences in this article is applicable to all Oracle versions using classic auditing setup.


To check which tables are currently being audited, use the views DBA_OBJ_AUDIT_OPTS and DBA_PRIV_AUDIT_OPTS.

DBA_PRIV_AUDIT_OPTS describes current system privileges being audited across the system and by user. USERNAME can hold three different values: 

  1. The actual user name if by user auditing
  2. ANY CLIENT if access by a proxy on behalf of a client is being audited; 
  3. NULL for system-wide auditing

DBA_OBJ_AUDIT_OPTS describes auditing options on all objects. 

If no objects or system privileges is being audited, the queries will return zero rows as in the examples below:
SELECT *
FROM DBA_PRIV_AUDIT_OPTS;

no rows selected

SELECT *
FROM DBA_OBJ_AUDIT_OPTS;

no rows selected

Let's start auditing an object:

AUDIT ALL ON SCOTT.BASELINE_STG_TBL;

Audit succeeded.

You can also be more specific and only update certain actions:
AUDIT UPDATE,DELETE,INSERT ON SCOTT.BASELINE_STG_TBL;

Audit succeeded.

Verify that audit is enabled:
SELECT *
FROM DBA_OBJ_AUDIT_OPTS
WHERE OWNER = 'SCOTT'
AND object_name='BASELINE_STG_TBL';

OWNER OBJECT_NAME OBJECT_TYPE ALT AUD COM DEL GRA IND INS LOC REN SEL UPD REF EXE CRE REA WRI FBK
SCOTT BASELINE_STG_TBL TABLE S/S S/S S/S S/S S/S S/S S/S S/S S/S S/S S/S -/- -/- -/- -/- -/- S/S


The notation 'S/S' in the different columns of the DBA_OBJ_AUDIT_OPTS is "frequency" where frequency is either "By Session" (S) or "By Access" (A).

The placement of the hyphen, the "S" or the "A" indicates under what circumstances the auditing should be performed, as outlined below:
-/-: no auditing
S/-: auditing whenever successful
-/S: auditing whenever not successful

As can be seen by the result above, by default, auditing is done by SESSION, both for successful and unsuccessful attempts.
Let's turn off auditing for SELECTs
NOAUDIT SELECT ON SCOTT.BASELINE_STG_TBL;

Noaudit succeeded.

Verify that queries on the table are now not being audited:
SELECT *
 FROM DBA_OBJ_AUDIT_OPTS
 WHERE OWNER = 'SCOTT'
 AND object_name='BASELINE_STG_TBL';
OWNER OBJECT_NAME OBJECT_TYPE ALT AUD COM DEL GRA IND INS LOC REN SEL UPD REF EXE CRE REA WRI FBK
SCOTT BASELINE_STG_TBL TABLE S/S S/S S/S S/S S/S S/S S/S S/S S/S -/- S/S -/- -/- -/- -/- -/- S/S

Notice that the SEL column now shows a hyphen (-) since the privilege is not audited anymore.

The following statement
AUDIT SELECT ON SCOTT.BASELINE_STG_TBL BY ACCESS WHENEVER NOT SUCCESSFUL;
Would result in
OWNER OBJECT_NAME OBJECT_TYPE ALT AUD COM DEL GRA IND INS LOC REN SEL UPD REF EXE CRE REA WRI FBK
SCOTT BASELINE_STG_TBL TABLE S/S S/S S/S S/S S/S S/S S/S S/S S/S -/A S/S -/- -/- -/- -/- -/- S/S

and
AUDIT SELECT ON SCOTT.COUNTRY_TABLE BY ACCESS WHENEVER SUCCESSFUL;
would result in
OWNER OBJECT_NAME OBJECT_TYPE ALT AUD COM DEL GRA IND INS LOC REN SEL UPD REF EXE CRE REA WRI FBK
SCOTT BASELINE_STG_TBL TABLE S/S S/S S/S S/S S/S S/S S/S S/S S/S A/- S/S -/- -/- -/- -/- -/- S/S


Keep in mind that mandatory auditing is always turned on. 
Oracle 12.2 Documentation for DBA_OBJ_AUDIT_OPTS can be found here

Monday, December 15, 2014

How to solve "ORA-06502: PL/SQL: numeric or value error" when cloning a database

While attempting to clone an Oracle 11gR2 production database, Oracle returned "ORA-06502: PL/SQL: numeric or value error".

The clone proceeded nicely up until RMAN attempted to set the db_unique_name. After this point, the clone failed, see error message output below:
Oracle instance started

Total System Global Area    8551575552 bytes

Fixed Size                     2263488 bytes
Variable Size               1107297856 bytes
Database Buffers            7415529472 bytes
Redo Buffers                  26484736 bytes

contents of Memory Script:
{
   sql clone "alter system set  db_name =
   ''testdb01'' comment=
   ''Reset to original value by RMAN'' scope=spfile";
   sql clone "alter system reset  db_unique_name scope=spfile";
   shutdown clone immediate;
}

executing Memory Script

sql statement: alter system set  db_name =  ''testdb01'' comment= ''Reset to original value by RMAN'' scope=spfile

sql statement: alter system reset  db_unique_name scope=spfile

Oracle instance shut down


RMAN-00571: ===========================================================
RMAN-00569: =============== ERROR MESSAGE STACK FOLLOWS ===============
RMAN-00571: ===========================================================
RMAN-03002: failure of Duplicate Db command at 12/11/2014 13:20:45
RMAN-05501: aborting duplication of target database
RMAN-06136: ORACLE error from auxiliary database: ORA-06502: PL/SQL: numeric or value error
The trace file also adds the following line to the previous lines:
ORA-06512: at "SYS.X$DBMS_BACKUP_RESTORE", line 5567

The culprit seems to be that my production database and the auxiliary database had at some point in the past been part of a Data Guard setup.
By looking at the registered databases in the recovery catalog, this could indeed be verified:

rman target / catalog uid/pwd@rmancat 

Recovery Manager: Release 11.2.0.4.0 - Production on Mon Dec 15 11:33:55 2014

Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.
 
connected to target database: proddb01 (DBID=3046916437)
connected to recovery catalog database

RMAN> set echo on;
2> list db_unique_name of database;
4> exit
echo set on
List of Databases

DB Key  DB Name  DB ID            Database Role    Db_unique_name
------- ------- ----------------- ---------------  ------------------
133048143 proddb01     3046916437       PRIMARY          proddb01
133048143 proddb01     3046916437       STANDBY          testdb01

Solution:
In this case, this old association to an obsolete standby database could be removed altogether.
I therefore unregistered the unique database from the recovery catalog:
RMAN> unregister db_unique_name 'testdb01';

database db_unique_name is "testdb01", db_name is "proddb01" and DBID is 3046916437

Want to unregister the database with target db_unique_name (enter YES or NO)? yes
database with db_unique_name testdb01 unregistered from the recovery catalog

After this was done, I restarted the clone, and the error was no longer thrown and the script continued as expected.

If you are in a slightly different position, and have several primary databases with the same unique name, you need a different approach. Consider the following example:
RMAN> list db_unique_name of database;

List of Databases

DB Key  DB Name  DB ID            Database Role    Db_unique_name
------- ------- ----------------- ---------------  ------------------
376254740 PDB01    3895530761       PRIMARY          PDB01
380374509 PDB01    3902464629       PRIMARY          PDB01
383100641 PDB01    3906391689       PRIMARY          PDB01

RMAN> SET DBID 3895530761;

executing command: SET DBID
database name is "PDB01" and DBID is 3895530761

RMAN> UNREGISTER DB_UNIQUE_NAME PDB01;

database db_unique_name is "PDB01", db_name is "PDB01" and DBID is 3895530761

Want to unregister the database with target db_unique_name (enter YES or NO)? yes

RMAN-00571: ===========================================================
RMAN-00569: =============== ERROR MESSAGE STACK FOLLOWS ===============
RMAN-00571: ===========================================================
RMAN-06004: ORACLE error from recovery catalog database: RMAN-20244: can not change currently connected database db_unique_name
RMAN> exit

Solution is to still explicitly set DBID, but then execute "unregister database" instead, like this:

RMAN> unregister database;

database name is "PDB01" and DBID is 3895530761

Do you really want to unregister the database (enter YES or NO)? yes

database unregistered from the recovery catalog

RMAN> SET DBID 3902464629;
executing command: SET DBID
database name is "PDB01" and DBID is 3902464629 

RMAN> unregister database;
database name is "PDB01" and DBID is 3902464629

Do you really want to unregister the database (enter YES or NO)? YES

RMAN> list db_unique_name of database;

List of Databases

DB Key  DB Name  DB ID            Database Role    Db_unique_name

------- ------- ----------------- ---------------  ------------------
383100641 PDB01    3906391689       PRIMARY          PDB01

We are left with only one unique db name, which is what we want.

Thursday, December 4, 2014

How to work around ORA-00845: MEMORY_TARGET not supported on this system during startup

On Linux platforms, you need to adjust the size of the shared memory file system (/dev/shm) to match the size of your memory_target or memory_max_target. If not you will see the following error:

SQL> startup mount

ORA-00845: MEMORY_TARGET not supported on this system

To adjust the size, open the file /etc/fstab in an editor:

vi /etc/fstab

At the line where you see the tmpfs file system specified, add the size after the keyword "defaults". In the example below, I would like to use a memory_target of 10g, so I add "10g". Do not use a capital letter G, but simply a "g":
tmpfs                   /dev/shm                tmpfs   defaults,size=10g        0 0

Then, remount the file system:
mount –o remount /dev/shm



Monday, December 1, 2014

How to find and change the default temporary tablespace and default tablespace for a database instance


set lines 200
col description format a50
col property_value format a30
col property_name format a30
SELECT * 
FROM DATABASE_PROPERTIES
WHERE PROPERTY_NAME LIKE '%TABLESPACE%';

To change the default temporary tablespace, use
alter database default temporary tablespace tmp;

To change the default tablespace, use
alter database default tablespace user_data;

How to setup Oracle Net Encryption for non-JDBC or OCI (thick) JDBC client

Since June 2013, SQL Net Encryption is a part of the normal Oracle EE license, as opposed to the Advanced Security Option.

Add the following to your server’s sqlnet.ora file:
sqlnet.encryption_server=required
sqlnet.encryption_types_server=AES128

Add the following to your client’s sqlnet.ora file:

SQLNET.ENCRYPTION_CLIENT = accepted

Note:
A list of encryption algorithms can be stated on each side, and the first one common to both client and server in the list will be chosen.

Verify that SQL Net Encryption works

In client’s sqlnet.ora:
ADR_BASE = C:\app\k90387
TRACE_LEVEL_CLIENT = ADMIN

This above will create an ADR directory structure on the client, in my case trace files are written to
 c:\app\vegard\oradiag_vegard\diag\clients\user_vegard\host_3450395457_76\trace

Create a session against the database:

SQL> connect vegard/vegard@oras
Connected.
SQL> exit

Open your windows explorer and look in the folder
c:\app\vegard\oradiag_vegard\diag\clients\user_vegard\host_3450395457_76\trace
You'll now see two files: one .trc file and one .trm file
Open the .trc file in a text editor, and search for the following:
2014-11-28 14:11:13.374358 :  -> PARAMETER TABLE HAS THE FOLLOWING CONTENTS <-
2014-11-28 14:11:13.374375 :   SQLNET.ENCRYPTION_CLIENT = accepted
2014-11-28 14:11:13.374392 :   ADR_BASE = C:\app\vegard
.
.
.
2014-11-28 13:48:28.033764 : na_tns:  authentication is not active
2014-11-28 13:48:28.033781 : na_tns:  encryption is active, using AES128
2014-11-28 13:48:28.033797 : na_tns:  crypto-checksumming is not active
Note that neither authentication nor crypto-checksumming is active, but encryption is. As expected.

Sources:

  • Orafaq
  • Oracle Documentation

  • Thursday, November 20, 2014

    How to flash the database back to a guaranteed restore point

    After a week of testing their new release, my customer wanted their database reset to the state it was previously in.
    Earlier this week, I created a restore point of type GUARANTEED FLASHBACK.

    Here is how I restored a database using flashback database technology. It was, as expected, very quick. Only a few seconds to flash back 14 GB of changes.

    Connect to Recovery Manager:
    oracle@myserver:[TESTDB01]# rman target / catalog uid/pwd@rmancat
    
    Recovery Manager: Release 11.2.0.4.0 - Production on Thu Nov 20 16:06:44 2014
    
    connected to target database: TESTDB01 (DBID=411134280, not open)
    connected to recovery catalog database
    
    RMAN> list restore point all;
    
    SCN              RSP Time  Type          Time         Name
    ---------------- --------- ----------   ---------     ----
    153050263689                GUARANTEED  17-NOV-14     AKSEPT_TEST_START
    

    Start the flashback operation:
    RMAN> FLASHBACK DATABASE TO RESTORE POINT AKSEPT_TEST_START;
    Starting flashback at 20-NOV-14
    allocated channel: ORA_SBT_TAPE_1
    channel ORA_SBT_TAPE_1: SID=585 device type=SBT_TAPE
    channel ORA_SBT_TAPE_1: Data Protection for Oracle: version 6.3.0.0
    allocated channel: ORA_DISK_1
    channel ORA_DISK_1: SID=683 device type=DISK
    
    starting media recovery
    
    archived log for thread 1 with sequence 4651 is already on disk as file /u04/fast_recovery_area/TESTDB01/archivelog/2014_11_17/o1_mf_1_4651_b6m91zog_.arc
    media recovery complete, elapsed time: 00:00:01
    Finished flashback at 20-NOV-14 
    
    RMAN> ALTER DATABASE OPEN RESETLOGS;
    
    database opened
    new incarnation of database registered in recovery catalog
    starting full resync of recovery catalog
    full resync complete
    RMAN> exit
    


    -- all done --

    From alert.log:
    Completed: ALTER DATABASE   MOUNT
    Thu Nov 20 16:10:37 2014
    alter database recover datafile list clear
    Completed: alter database recover datafile list clear
    RMAN flashback database to before scn 153050263690 in incarnation 2
    Flashback Restore Start
    Thu Nov 20 16:12:11 2014
    Flashback Restore Complete
    Flashback Media Recovery Start
    started logmerger process
    Parallel Media Recovery started with 8 slaves
    Thu Nov 20 16:12:22 2014
    Flashback Media Recovery Log /u04/fast_recovery_area/TESTDB01/archivelog/2014_11_17/o1_mf_1_4651_b6m91zog_.arc
    Thu Nov 20 16:12:22 2014
    Incomplete Recovery applied until change 153050263690 time 11/17/2014 07:53:33
    Flashback Media Recovery Complete
    Completed: RMAN flashback database to before scn 153050263690 in incarnation 2
    Thu Nov 20 16:13:29 2014
    alter database open resetlogs
    RESETLOGS after incomplete recovery UNTIL CHANGE 153050263690
    Archived Log entry 4827 added for thread 1 sequence 4826 ID 0x18811648 dest 1:
    Archived Log entry 4828 added for thread 1 sequence 4823 ID 0x18811648 dest 1:
    Archived Log entry 4829 added for thread 1 sequence 4822 ID 0x18811648 dest 1:
    Archived Log entry 4830 added for thread 1 sequence 4827 ID 0x18811648 dest 1:
    Archived Log entry 4831 added for thread 1 sequence 4824 ID 0x18811648 dest 1:
    Archived Log entry 4832 added for thread 1 sequence 4825 ID 0x18811648 dest 1:
    Clearing online redo logfile 1 /u03/oradata/TESTDB01/redo01.log
    Clearing online log 1 of thread 1 sequence number 4826
    Clearing online redo logfile 1 complete
    Clearing online redo logfile 2 /u03/oradata/TESTDB01/redo02.log
    Clearing online log 2 of thread 1 sequence number 4823
    Clearing online redo logfile 2 complete
    Clearing online redo logfile 3 /u03/oradata/TESTDB01/redo03.log
    Clearing online log 3 of thread 1 sequence number 4822
    Thu Nov 20 16:13:41 2014
    Clearing online redo logfile 3 complete
    Clearing online redo logfile 4 /u03/oradata/TESTDB01/redo04.log
    Clearing online log 4 of thread 1 sequence number 4827
    Clearing online redo logfile 4 complete
    Clearing online redo logfile 5 /u03/oradata/TESTDB01/redo05.log
    Clearing online log 5 of thread 1 sequence number 4824
    Clearing online redo logfile 5 complete
    Clearing online redo logfile 6 /u03/oradata/TESTDB01/redo06.log
    Clearing online log 6 of thread 1 sequence number 4825
    Thu Nov 20 16:13:52 2014
    Clearing online redo logfile 6 complete
    Resetting resetlogs activation ID 411113032 (0x18811648)
    Online log /u03/oradata/TESTDB01/redo01.log: Thread 1 Group 1 was previously cleared
    Online log /u03/oradata/TESTDB01/redo02.log: Thread 1 Group 2 was previously cleared
    Online log /u03/oradata/TESTDB01/redo03.log: Thread 1 Group 3 was previously cleared
    Online log /u03/oradata/TESTDB01/redo04.log: Thread 1 Group 4 was previously cleared
    Online log /u03/oradata/TESTDB01/redo05.log: Thread 1 Group 5 was previously cleared
    Online log /u03/oradata/TESTDB01/redo06.log: Thread 1 Group 6 was previously cleared
    Thu Nov 20 16:13:52 2014
    Setting recovery target incarnation to 3
    

    Wednesday, November 19, 2014

    How to increase the SMB space budget

    When the message below shows up in the database alert.log, you should increase the SMB space budget.

    Message:
    SPM: SMB space usage (13523353600) exceeds 10.000000% of SYSAUX size (15728640000).
    
    Command:
    exec dbms_spm.configure('Space_budget_percent', 30);
    

    Monday, November 3, 2014

    How to create a tarball - short description

    To create a tarball, for example of an Oracle Home, do the following:
    # become root
    su - 
    # cd to the directory in which you keep your files you'd like to tar up:
    cd /u01/oracle/product/11204
    # create the tarball, place it in the parent directory:
    tar cvf ../oracle11204.tar *
    

    You could also add compression at the same time:
    tar -cvzf ../oracle11204.tar.tgz .
    
    To create a tarball of the directory /tmp/dbscr and any file(s) in it:
    cd /tmp
    tar cvf mytarball.tar dbscr
    dbscr/
    dbscr/file1.txt
    dbscr/file2.rsp
    dbscr/file3.ora
    

    Saturday, November 1, 2014

    Step by step: how to switchover from primary to standby with Oracle 10g

    Based on the guide found in the official Oracle 10g documents found here

    This is a classic Oracle 10g two-node Physical standby Data Guard setup:

    Primary database name: proddb01
    Standby database name: stby01

    STEP 1: Verify that it is possible to fail over.
    On primary database (proddb01):
    SQL> SELECT SWITCHOVER_STATUS FROM V$DATABASE;
    
    SWITCHOVER_STATUS
    --------------------
    SESSIONS ACTIVE
    

    A value of TO STANDBY or SESSIONS ACTIVE indicates that the primary database is ready to be switched to the standby role.
    In my case, the output was SESSIONS ACTIVE. In this case, check if this is because of a) active SQL sessions or b) active user sessions.
    The section "Problems switching over to a standby database, section A.4.2 and A.4.3" gives good examples on how to clean up your primary before attempting to switch over.

    It seems like you can still successfully perform a switchover by appending the WITH SESSION SHUTDOWN clause to the ALTER DATABASE COMMIT TO SWITCHOVER TO PHYSICAL STANDBY statement, and that is exactly what I did:

    STEP 2: Instruct the primary database to take the role as the standby database.

    On the primary (proddb01):
    ALTER DATABASE COMMIT TO SWITCHOVER TO PHYSICAL STANDBY WITH SESSION SHUTDOWN;
    

    From primary (proddb01) alert log:

    idle dispatcher 'D000' terminated, pid = (16, 1)
    Tue Oct 28 19:13:39 2014
    Switchover: Complete - Database shutdown required (proddb01)
    Tue Oct 28 19:13:39 2014
    Completed: ALTER DATABASE COMMIT TO SWITCHOVER TO PHYSICAL STANDBY WITH SESSION SHUTDOWN
    

    From the standby (stby01) alert log:
    -- Connected User is Valid
    RFS[40]: Assigned to RFS process 7078566
    RFS[40]: Identified database type as 'physical standby'
    RFS[40]: Successfully opened standby log 7: '/u02/oradata/stby01/stb_redo7.log
    Tue Oct 28 19:10:57 2014
    Media Recovery Log /u04/oradata/stby01/archive/log1_75389_681750063.arc
    Media Recovery Waiting for thread 1 sequence 75390
    Tue Oct 28 19:13:31 2014
    Redo Shipping Client Connected as PUBLIC
    -- Connected User is Valid
    RFS[41]: Assigned to RFS process 34669144
    RFS[41]: Identified database type as 'physical standby'
    RFS[41]: Archived Log: '/u04/oradata/stby01/archive/log1_75390_681750063.arc'
    Tue Oct 28 19:13:32 2014
    Media Recovery Log /u04/oradata/stby01/archive/log1_75390_681750063.arc
    Identified End-Of-Redo for thread 1 sequence 75390
    Tue Oct 28 19:13:32 2014
    Media Recovery End-Of-Redo indicator encountered
    Tue Oct 28 19:13:32 2014
    Media Recovery Applied until change 142570810888
    Tue Oct 28 19:13:32 2014
    MRP0: Media Recovery Complete: End-Of-REDO (stby01)
    Resetting standby activation ID 1529144623 (0x5b24e52f)
    Tue Oct 28 19:13:35 2014
    MRP0: Background Media Recovery process shutdown (stby01)
    

    Step 3: shutdown the database and start it in mounted mode.
    On primary (proddb01):
    shutdown abort
    startup mount
    
    From the primary (proddb01) alert log:
    Tue Oct 28 19:15:37 2014
    Successful mount of redo thread 1, with mount id 1709512659
    Tue Oct 28 19:15:37 2014
    Physical Standby Database mounted.
    Starting control autobackup
    Control autobackup written to DISK device
            handle '/u01/oracle/product/ora10g/dbs/c-1529124399-20141028-12'
    Completed: ALTER DATABASE MOUNT
    


    Step 4: verify the current status.

    On the standby (stby01):
    SQL> SELECT SWITCHOVER_STATUS FROM V$DATABASE;
    
    SWITCHOVER_STATUS
    --------------------
    TO PRIMARY
    

    A value of TO PRIMARY or SESSIONS ACTIVE indicates that the standby database is ready to be switched to the primary role. If neither of these values is returned, verify that Redo Apply is active and that redo transport is configured and working properly. Continue to query this column until the value returned is either TO PRIMARY or SESSIONS ACTIVE.

    Step 5: Instruct the standby database to take on the role as a primary database.
    On the standby (stby01):
    ALTER DATABASE COMMIT TO SWITCHOVER TO PRIMARY;
    
    From the standby (stby01) alert log:
    -- Connected User is Valid
    RFS[41]: Assigned to RFS process 34669144
    RFS[41]: Identified database type as 'physical standby'
    RFS[41]: Archived Log: '/u04/oradata/stby01/archive/log1_75390_681750063.arc'
    Tue Oct 28 19:13:32 2014
    Media Recovery Log /u04/oradata/stby01/archive/log1_75390_681750063.arc
    Identified End-Of-Redo for thread 1 sequence 75390
    Tue Oct 28 19:13:32 2014
    Media Recovery End-Of-Redo indicator encountered
    Tue Oct 28 19:13:32 2014
    Media Recovery Applied until change 142570810888
    Tue Oct 28 19:13:32 2014
    MRP0: Media Recovery Complete: End-Of-REDO (stby01)
    Resetting standby activation ID 1529144623 (0x5b24e52f)
    Tue Oct 28 19:13:35 2014
    MRP0: Background Media Recovery process shutdown (stby01)
    Tue Oct 28 19:18:43 2014
    ALTER DATABASE SWITCHOVER TO PRIMARY (stby01)
    Tue Oct 28 19:18:43 2014
    If media recovery active, switchover will wait 900 seconds
    SwitchOver after complete recovery through change 142570810888
    Online log /u02/oradata/stby01/redo1.log: Thread 1 Group 4 was previously cleared
    Online log /u02/oradata/stby01/redo2.log: Thread 1 Group 5 was previously cleared
    Online log /u02/oradata/stby01/redo3.log: Thread 1 Group 6 was previously cleared
    Standby became primary SCN: 142570810886
    Converting standby mount to primary mount.
    Tue Oct 28 19:18:43 2014
    Switchover: Complete - Database mounted as primary (stby01)
    Completed: ALTER DATABASE COMMIT TO SWITCHOVER TO PRIMARY
    Tue Oct 28 19:18:43 2014
    ARC0: STARTING ARCH PROCESSES
    ARC2: Archival started
    ARC0: STARTING ARCH PROCESSES COMPLETE
    ARC2 started with pid=15, OS id=8847906
    Tue Oct 28 19:19:41 2014
    ALTER DATABASE OPEN
    
    The primary database (proddb01) is from now on considering itself to be the physical standby database.


    From the old primary (proddb01) database alert log:
    Tue Oct 28 19:15:37 2014
    Physical Standby Database mounted.
    Starting control autobackup
    Control autobackup written to DISK device
            handle '/u01/oracle/product/ora10g/dbs/c-1529124399-20141028-12'
    Completed: ALTER DATABASE   MOUNT
    Tue Oct 28 19:26:10 2014
    Using STANDBY_ARCHIVE_DEST parameter default value as /u01/oracle/admin/proddb01/archive/
    Tue Oct 28 19:26:19 2014
    Starting control autobackup
    Control autobackup written to SBT_TAPE device
            comment 'API Version 2.0,MMS Version 5.3.3.0',
            media '1362'
            handle 'c-1529124399-20141028-13'
    

    Step 6: Verify that the former standby database now has the primary role.
    On stby01:
    SQL> SELECT DB_UNIQUE_NAME,NAME,DATABASE_ROLE FROM V$DATABASE;
    
    DB_UNIQUE_NAME                 NAME           DATABASE_ROLE
    ------------------------------ -------------- ----------------
    stby01                          proddb01           PRIMARY
    


    After switchover, Oracle complained about some temporary files:

    ORA-01187: cannot read from file 201 because it failed verification tests
    ORA-01110: data file 201: '/u02/oradata/stby01/temp01.dbf'
    
    
    
    SQL> 
      1  select tf.file#,tf.ts#,tf.status,tf.enabled, tf.bytes/1024/1024,tf.name "file_name",ts.name "ts_name"
      2  from v$tempfile tf, v$tablespace ts
      3* where tf.ts# = ts.ts#
    
         FILE#        TS# STATUS  ENABLED    TF.BYTES/1024/1024 file_name                              ts_name
    ---------- ---------- ------- ---------- ------------------ -------------------------------------- --------------------
             1          3 ONLINE  READ WRITE              32767 /u02/oradata/stby01/temp01.dbf          TEMP
             2          8 ONLINE  READ WRITE                100 /u02/oradata/stby01/EDPROD_iastemp.dbf  EDPROD_IAS_TEMP
             3          3 ONLINE  READ WRITE               9900 /u02/oradata/stby01/temp02.dbf          TEMP
    
    SQL> save temp_tabspc_overview.sql
    Created file temp_tabspc_overview.sql
    
    SQL> drop tablespace EDPROD_IAS_TEMP including contents and datafiles;
    
    Tablespace dropped.
    
    SQL> @temp_tabspc_overview.sql
    
         FILE#        TS# STATUS  ENABLED    TF.BYTES/1024/1024 file_name                      ts_name
    ---------- ---------- ------- ---------- ------------------ ------------------------------ --------------------
             1          3 ONLINE  READ WRITE              32767 /u02/oradata/stby01/temp01.dbf  TEMP
             3          3 ONLINE  READ WRITE               9900 /u02/oradata/stby01/temp02.dbf  TEMP
    
    
    SQL> create temporary tablespace EDPROD_IAS_TEMP tempfile '/u02/oradata/stby01/EDPROD_iastemp.dbf' size 128M reuse autoextend on next 32M maxsize unlimited
    
    Tablespace created.
    
    SQL>  @temp_tabspc_overview.sql
    
         FILE#        TS# STATUS  ENABLED    TF.BYTES/1024/1024 file_name                              ts_name
    ---------- ---------- ------- ---------- ------------------ -------------------------------------- --------------------
             1          3 ONLINE  READ WRITE              32767 /u02/oradata/stby01/temp01.dbf          TEMP
             2          8 ONLINE  READ WRITE                128 /u02/oradata/stby01/EDPROD_iastemp.dbf  EDPROD_IAS_TEMP
             3          3 ONLINE  READ WRITE               9900 /u02/oradata/stby01/temp02.dbf          TEMP
    
    
    SQL> alter database default temporary tablespace EDPROD_IAS_TEMP;
    
    Database altered.
    
    SQL>  drop tablespace TEMP including contents and datafiles;
    
    Tablespace dropped.
    
    SQL> create temporary tablespace TEMP tempfile '/u02/oradata/stby01/temp01.dbf' size 128M reuse autoextend on next 32M maxsize unlimited;
    
    Tablespace created.
    
    SQL> @temp_tabspc_overview.sql
    
         FILE#        TS# STATUS  ENABLED    TF.BYTES/1024/1024 file_name                              ts_name
    ---------- ---------- ------- ---------- ------------------ -------------------------------------- --------------------
             1          3 ONLINE  READ WRITE                128 /u02/oradata/stby01/temp01.dbf          TEMP
             2          8 ONLINE  READ WRITE                128 /u02/oradata/stby01/EDPROD_iastemp.dbf  EDPROD_IAS_TEMP
    
    

    Wednesday, October 22, 2014

    Step by step: how to create a physical standby database with Oracle 10g

    I recently had to create an Oracle 10g standby database to support a simultaneous move and upgrade of the database.

    Below are the steps I followed to set it up.

    Prerequisites for these steps are
    * you have a working tape backup in place, and that you can perform redirected restores.
    * you have the same software installed on both servers, in my case it was Oracle EE version 10.2.0.4

    By "redirected restores" I mean that you are able to restore database backups through rman to a host different from the one where the backup was taken.
    I will not explain the details around details such as standby redo log files, log transportation methods etc; there are plenty of good sources for this to be found on the internet.


    1. prepare the primary database parameters:

    LOG_ARCHIVE_CONFIG='DG_CONFIG=(proddb01,stby01)'
    LOG_ARCHIVE_DEST_1='LOCATION=/u01/oracle/admin/proddb01/archive/ VALID_FOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=proddb01'
    LOG_ARCHIVE_DEST_2='SERVICE=stby01 LGWR ASYNC VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=stby01'
    LOG_ARCHIVE_DEST_STATE_1=ENABLE
    LOG_ARCHIVE_DEST_STATE_2=DEFER
    LOG_ARCHIVE_FORMAT=%t_%s_%r.arc
    LOG_ARCHIVE_MAX_PROCESSES=30
    STANDBY_FILE_MANAGEMENT=AUTO

    # The following parameters will only be applicable when the primary is turned into a standby
    # We put them there to maker life easier in case of such event
    FAL_SERVER=stby01
    FAL_CLIENT=proddb01
    DB_FILE_NAME_CONVERT='stby01','proddb01'
    LOG_FILE_NAME_CONVERT='/u04/oradata/stby01/archive/','/u01/oracle/admin/proddb01/archive/'

    2. create standby redo log files on primary database:

    First, check the number of redo log groups currently in use:
    SQL> select group# ,members, status from v$log;
    
        GROUP#    MEMBERS STATUS
    
    ---------- ---------- ----------------
             4          1 ACTIVE
             5          1 ACTIVE
             6          1 CURRENT
    
    Oracle recommends to add standby redo log file groups with the same size as the largest member in any group. They also recommend that the number of standby redo log groups is the same as the number of redo log groups + 1.
    In my case, this means that I will add 4 standby redo log groups of 512M size each:
    SQL> ALTER DATABASE ADD STANDBY LOGFILE GROUP 7 ('/u02/oradata/proddb01/stb_redo7.log') size 512M;
    
    Database altered.
    
    SQL> ALTER DATABASE ADD STANDBY LOGFILE GROUP 8 ('/u02/oradata/proddb01/stb_redo8.log') size 512M;
    
    SQL> select group# ,members, status from v$log;
    
    Database altered.
    
    SQL> ALTER DATABASE ADD STANDBY LOGFILE GROUP 9 ('/u02/oradata/proddb01/stb_redo9.log') size 512M;
    
    Database altered.
    
    SQL>  ALTER DATABASE ADD STANDBY LOGFILE GROUP 10 ('/u02/oradata/proddb01/stb_redo10.log') size 512M;
    
    Database altered.
    
    Verify that they were created:
    SQL> select group#,thread#,sequence#,archived,status from v$standby_log;
    
        GROUP#    THREAD#  SEQUENCE# ARC STATUS
    ---------- ---------- ---------- --- ----------
             7          0          0 YES UNASSIGNED
             8          0          0 YES UNASSIGNED
             9          0          0 YES UNASSIGNED
            10          0          0 YES UNASSIGNED
    
    3. enable force logging:
    ALTER DATABASE FORCE LOGGING;
    
    4. restart primary database
    STARTUP MOUNT
    
    Assuming that you have a valid tape backup solution in place, backup your current control file "for standby" using rman:
    rman target / catalog uid/pwd@rmancat
    run {
    allocate channel c1 type 'sbt_tape' maxpiecesize 4000M;
    BACKUP CURRENT CONTROLFILE FOR STANDBY;
    release channel c1;
    
    5. Open the database, and switch the current logfile This must be done so that the last log file is indeed older than your backup controfile that you created in the previous step:
    SQL> ALTER DATABASE OPEN;
    SQL 'ALTER SYSTEM ARCHIVE LOG CURRENT';  # so backup is consistent and recoverable
    
    6. Finally, backup the latest archived redo log to tape:
    rman target / catalog uid/pwd@rmancat
    run {
    allocate channel c1 type 'sbt_tape' maxpiecesize 4000M;
    BACKUP ARCHIVELOG ALL NOT BACKED UP 1 TIMES;
    release channel c1;
    
    7. Set up SQL*net connection ...by adding an entry in the primary database's tnsnames.ora:
    stby01 =
      (DESCRIPTION =
        (ADDRESS = (PROTOCOL = TCP)(HOST = psu0erdb01)(PORT = 1521))
        (CONNECT_DATA =
          (SERVER = DEDICATED)
          (SERVICE_NAME = stby01)
        )
      )
    
    8. Prepare the standby database parameters. # The db_name must from now on match your primary database db_name db_name='proddb01' # The db_unique_name is the name to which you will typically refer to the standby database db_unique_name='stby01' log_archive_config='DG_CONFIG=(proddb01,stby01)' log_archive_format=log%t_%s_%r.arc log_archive_dest_1='LOCATION=/u04/oradata/ stby01/archive VALID_FOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME= stby01' log_archive_dest_2='SERVICE=proddb01 LGWR ASYNC VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=proddb01' log_archive_dest_state_1=enable log_archive_dest_state_2=defer remote_login_passwordfile='EXCLUSIVE' standby_file_management=auto fal_server=proddb01 fal_client=stby01 db_file_name_convert='proddb01','stby01' log_file_name_convert='proddb01','stby01' 9. shutdown the to-become standby database, open it in nomount-mode:
    shutdown immediate
    startup nomount pfile='your_pfile.ora'
    
    Your standby database is now ready to be cloned from your primary. 10. Create an rman script: in file duplicate_for_standby.sh
    export ORACLE_SID=stby01
    export ORACLE_HOME=/u01/oracle/product/10204
    export NLS_DATE_FORMAT='DD.MM.YYYY HH24:MI:SS'
    export NLS_LANG=AMERICAN_NORWAY.WE8ISO8859P15
    rman target sys/password@proddb01 catalog uid/pwd@rmancat auxiliary / cmdfile='duplicate_for_standby.cmd' log='duplicate_for_standby.log' trace='duplicate_for_standby.trc'
    exit
    
    In file duplicate_for_standby.cmd:
    run {
    ALLOCATE AUXILIARY CHANNEL c1 TYPE 'SBT_TAPE';
    ALLOCATE AUXILIARY CHANNEL c2 TYPE 'SBT_TAPE';
    ALLOCATE AUXILIARY CHANNEL c3 TYPE 'SBT_TAPE';
    ALLOCATE AUXILIARY CHANNEL c4 TYPE 'SBT_TAPE';
    ALLOCATE AUXILIARY CHANNEL c5 TYPE 'SBT_TAPE';
    ALLOCATE AUXILIARY CHANNEL c6 TYPE 'SBT_TAPE';
    duplicate target database for standby
    dorecover;
    }
    exit
    
    chmod 755 duplicate_for_standby.sh
    
    11. Start the cloning script in the background:
    nohup ./duplicate_for_standby.sh &
    
    Follow the progress with
    tail -f duplicate_for_standby.log
    
    As the directive "dorecover" indicates, rman will create a clone from the primary database, recover it, and leave the recovered database in mounted state. 12. Enable log transport services on the primary database:
    ALTER SYSTEM SET LOG_ARCHIVE_DEST_STATE_2=ENABLE SCOPE=BOTH;
    
    As a recap, this will instruct Oracle to ship logs to LOG_ARCHIVE_DEST_2, which is defined as a service that you have made known to your primary server through an entry in tnsnames.ora:
    LOG_ARCHIVE_DEST_2='SERVICE=stby01 LGWR ASYNC VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=stby01'
    
    13. Check that your standby is applying logs. You can use the script found here Pay particularly attention that the following section looks like this:
    Is the MRP process running?
    PROCESS   STATUS
    --------- ------------
    
    MRP0      WAIT_FOR_LOG
    
    Crosscheck that with a look at the current archived log status:
    set lines 200
    col name format a60
    alter session set nls_language='american';
    alter session set nls_date_format='dd.mm.yyyy hh24:mi:ss';
    SELECT SEQUENCE#,NAME,STANDBY_DEST,ARCHIVED,APPLIED,DELETED,STATUS,COMPLETION_TIME
    FROM V$ARCHIVED_LOG
    ORDER BY SEQUENCE# ASC
    /
    
    The primary and standby should give similar views of the archived log situation: Standby:
    SEQUENCE# NAME                                                      STA ARC APP DEL S COMPLETION_TIME
    ---------- -------------------------------------------------------- --- --- --- --- - -------------------
    
    75072 /u04/oradata/stby01/archive/log1_75072_681750063.arc          NO  YES YES NO  A 22.10.2014 12:26:07
    75073 /u04/oradata/stby01/archive/log1_75073_681750063.arc          NO  YES YES NO  A 22.10.2014 12:26:37
    
    Primary. Notice how the archived logs are sent to two destinations at every log switch:
    SEQUENCE# NAME                                                      STA ARC APP DEL S COMPLETION_TIME
    ---------- -------------------------------------------------------- --- --- --- --- - -------------------
    
    75072 stby01                                                        YES YES YES NO  A 22.10.2014 12:26:06
    75072 /u01/oracle/admin/proddb01/archive/1_75072_681750063.arc      NO  YES NO  NO  A 22.10.2014 12:26:08
    75073 stby01                                                        YES YES YES NO  A 22.10.2014 12:26:37
    75073 /u01/oracle/admin/proddb01/archive/1_75073_681750063.arc      NO  YES NO  NO  A 22.10.2014 12:26:37
    
    From the standby database's alert log, it's clear that logs are being applied:
    Wed Oct 22 13:26:13 2014
    Media Recovery Log /u04/oradata/stby01/archive/log1_75074_681750063.arc
    Wed Oct 22 13:26:33 2014
    Media Recovery Waiting for thread 1 sequence 75075 (in transit)
    Wed Oct 22 13:26:39 2014
    Primary database is in MAXIMUM PERFORMANCE mode
    RFS[30]: Successfully opened standby log 7: '/u02/oradata/stby01/stb_redo7.log'
    Wed Oct 22 13:26:43 2014
    Media Recovery Log /u04/oradata/stby01/archive/log1_75075_681750063.arc
    Media Recovery Waiting for thread 1 sequence 75076 (in transit)
    
    Documentation used "Creating a Physical Standby Database" "Creating a Standby Database with Recovery Manager"



    Tuesday, October 21, 2014

    How to view stored scripts in RMAN

    Three different ways to print scripts stored in your recovery catalog:

    list all script names;
    list global script names;
    print script my_script;
    

    Friday, October 17, 2014

    Script example: create database

    CREATE DATABASE "mydb"
        MAXINSTANCES 8
        MAXLOGHISTORY 1
        MAXLOGFILES 16
        MAXLOGMEMBERS 3
        MAXDATAFILES 100
    DATAFILE '/u02/oradata/mydb/system01.dbf' SIZE 512M REUSE AUTOEXTEND ON NEXT  32M MAXSIZE UNLIMITED EXTENT MANAGEMENT LOCAL 
    SYSAUX DATAFILE '/u02/oradata/mydb/sysaux01.dbf' SIZE 512M REUSE AUTOEXTEND ON NEXT 32M MAXSIZE UNLIMITED 
    SMALLFILE DEFAULT TEMPORARY TABLESPACE TEMP TEMPFILE '/u02/oradata/mydb/temp01.dbf' SIZE 20M REUSE AUTOEXTEND ON NEXT 640K MAXSIZE UNLIMITED
    SMALLFILE UNDO TABLESPACE "UNDOTBS1" DATAFILE '/u02/oradata/mydb/undotbs01.dbf' SIZE 200M REUSE AUTOEXTEND ON NEXT 5120K MAXSIZE UNLIMITED
    CHARACTER SET AL32UTF8
    NATIONAL CHARACTER SET AL16UTF16
    LOGFILE GROUP 1 ('/u03/oradata/mydb/redo01.log') SIZE 2048M,
                 GROUP 2 ('/u03/oradata/mydb/redo02.log') SIZE 2048M,
                 GROUP 3 ('/u03/oradata/mydb/redo03.log') SIZE 2048M
    USER SYS IDENTIFIED BY "&&sysPassword"
    USER SYSTEM IDENTIFIED BY "&&systemPassword";
    

    Note 1:
    You can exchange "SMALLFILE" with "BIGFILE" for any tablespace, as long as they are locally managed with automatic segment space management.

    There are three exceptions to this rule: locally managed undo tablespaces, temporary tablespaces, and the SYSTEM tablespace does not have to use automatic segment space management; they *must* use manual segment space management but can still be created as BIGFILE. In one of my databases, I have the following setup:

    SELECT tablespace_name,bigfile,extent_management,segment_space_management 
    FROM dba_tablespaces;
    
    TABLESPACE_NAME                          BIGFILE   EXTENT_MANAGEMENT              SEGMENT_SPACE_MANA
    ---------------------------------------- --------- ------------------------------ ------------------
    SYSTEM                                   NO        LOCAL                          MANUAL
    SYSAUX                                   NO        LOCAL                          AUTO
    UNDOTBS1                                 YES       LOCAL                          MANUAL
    TEMP                                     YES       LOCAL                          MANUAL
    USERS                                    NO        LOCAL                          AUTO
    

    Note 2:
    The NATIONAL CHARACTER SET clause specifies the "national character set used to store data in columns specifically defined as NCHAR, NCLOB, or NVARCHAR2. Valid values are AL16UTF16 and UTF8. The default is AL16UTF16."

    Wednesday, October 15, 2014

    Why aren't other schemas' procedures showing in TOADs schema browser?

    Problem: User SCOTT has been granted SELECT on a number of tables belonging to another schema, OBM.
    They all show up neatly in TOADs schema browser.

    However, procedures and sequences are not visible. Why?

    Answer: lack of privileges.

    Solution: Try granting the following as user sys:

    GRANT SELECT ON OBM.sequence1 to SCOTT;
    GRANT DEBUG ON OBM.proceure1 to SCOTT;
    

    Refresh the schema browser - voila!

    To generate a list of objects with grant statements:

    SELECT 'GRANT DEBUG ON ' || OWNER || '.' || OBJECT_NAME || ' TO SCOTT;' 
    FROM DBA_PROCEDURES 
    WHERE OWNER = 'OBM' 
    AND OBJECT_TYPE='PROCEDURE';
    
    SELECT 'GRANT SELECT ON ' || SEQUENCE_OWNER || '.' || SEQUENCE_NAME || ' TO SCOTT;' 
    FROM DBA_SEQUENCES 
    WHERE SEQUENCE_OWNER = 'OBM';
    


    Alternatively, if acceptable in your environment you could grant select and debug on all sequences and procedures, respectively:
    GRANT SELECT ANY SEQUENCE TO SCOTT;
    GRANT DEBUG ANY PROCEDURE TO SCOTT;
    

    Thursday, October 9, 2014

    How to find hidden parameters in the database

    set lines 200
    col description format a70
    col value format a20
    col name format a30
    SELECT name,value,description from SYS.V$PARAMETER WHERE name  LIKE '\_%' ESCAPE '\';
    SELECT (translate(value,chr(13)||chr(10),' ')) FROM sys.v$parameter2  WHERE  UPPER(name) ='EVENT' AND  isdefault='FALSE';
    SELECT (translate(value,chr(13)||chr(10),' ')) from sys.v$parameter2 WHERE UPPER(name) = '_TRACE_EVENTS' AND isdefault='FALSE';
    

    If desirable, you can generate a "reset" script, which preserves your hidden parameters, like this:
    set lines 200
    set pages 0
    set feedback off
    set verify off
    set echo off
    set heading off
    set trimspool on
    spool original_hidden_params.sql
    select '-- original hidden parameter values' from dual;
    select 'alter system set "' || name || '"=' || value || ' scope=spfile;' from SYS.V$PARAMETER WHERE name  LIKE '\_%' ESCAPE '\';
    select 'exit' from dual;
    spool off
    spool reset_hidden_params.sql
    select '-- reset hidden parameter' from dual;
    select 'alter system reset "' || name || '" scope=spfile;' from SYS.V$PARAMETER WHERE name  LIKE '\_%' ESCAPE '\';
    select 'exit' from dual;
    exit
    

    To set a hidden parameter in Your instance, see this post.

    How to install Oracle Text

    Based on "Manual Installation, Deinstallation and Verification of Oracle Text 11gR2 (Doc ID 970473.1)" from My Oracle Support

    1. Install the CTXSYS schema:

    SQL> connect SYS/password as SYSDBA
    SQL> spool text_install.txt
    SQL> @?/ctx/admin/catctx.sql change_on_install SYSAUX TEMP NOLOCK
    

    2. Install the language-specific default preferences.
    There is script which creates language-specific default preferences for every language Oracle Text supports in $O_H/ctx/admin/defaults Directory

    Grep for your language, and you'll find your script easily:
    myserver>grep Norwegian *
    drdefn.sql:Rem      default preference for Norwegian
    
    Execute it as follows:
    SQL> connect "CTXSYS"/"change_on_install"
    SQL> @?/ctx/admin/defaults/drdefn.sql "NORWEGIAN";
    SQL> connect SYS/password as SYSDBA
    SQL> alter user ctxsys account lock password expire;
    SQL> spool off
    

    3. Verify your installation by running:
    connect SYS/password as SYSDBA
    
    set pages 1000
    col object_name format a40
    col object_type format a20
    col comp_name format a30
    column library_name format a8
    column file_spec format a60 wrap
    spool text_install_verification.log
    
    -- check on setup
    select comp_name, status, substr(version,1,10) as version from dba_registry where comp_id = 'CONTEXT';
    select * from ctxsys.ctx_version;
    select substr(ctxsys.dri_version,1,10) VER_CODE from dual;
    
    select count(*) from dba_objects where owner='CTXSYS';
    
    -- Get a summary count
    select object_type, count(*) from dba_objects where owner='CTXSYS' group by object_type;
    
    -- Any invalid objects
    select object_name, object_type, status from dba_objects where owner='CTXSYS' and status != 'VALID' order by object_name;
    
    spool off
    

    Valid output depends on your Oracle version, but for 11.2.0.3 it is:

    COMP_NAME                      STATUS                                       VERSION
    ------------------------------ -------------------------------------------- ----------------------------------------
    Oracle Text                    VALID                                        11.2.0.3.0
     
    
    VER_DICT                                 VER_CODE
    ---------------------------------------- ----------------------------------------
    11.2.0.3.0                               11.2.0.3.0
     
    
    VER_CODE
    ----------------------------------------
    11.2.0.3.0
    
    
      COUNT(*)
    ----------
           388
    
    
    OBJECT_TYPE            COUNT(*)
    -------------------- ----------
    INDEX                        63
    TYPE BODY                     6
    INDEXTYPE                     4
    PROCEDURE                     2
    TYPE                         35
    TABLE                        50
    VIEW                         77
    FUNCTION                      2
    LIBRARY                       1
    PACKAGE BODY                 63
    OPERATOR                      6
    PACKAGE                      74
    LOB                           2
    SEQUENCE                      3
    

    Tuesday, October 7, 2014

    How to create the PLUSTRACE role in order to use the AUTOTRACE feature in sqlplus


    Create the PLAN_TABLE in the schema you want to use it for (in this example, SCOTT):

    CONNECT SCOTT 
    @$ORACLE_HOME/rdbms/admin/utlxplan.sql 
    

    Create the PLUSTRACE role:
    CONNECT / AS SYSDBA 
    @$ORACLE_HOME/sqlplus/admin/plustrce.sql 
    

    Grant the PLUSTRACE role to SCOTT:
    CONNECT / AS SYSDBA 
    grant plustrace to scott;
    

    You are now able to use the autotrace feature of sqlplus for user SCOTT.

    Source: Oracle Documentation

    Monday, October 6, 2014

    How to display the currently used ORACLE_HOME from sqlplus



    Thanks to my former colleague Laurent Schneider for pointing out a way to display the currently used ORACLE_HOME from within sqlplus:

    set lines 200
    col oracle_home format a40
    set autoprint on
    var oracle_home varchar2(255)
    exec dbms_system.get_env('ORACLE_HOME',:ORACLE_HOME);
    
    PL/SQL procedure successfully completed.
    
    ORACLE_HOME
    ------------------------------
    
    /u01/oracle/product/11204
    

    Note: To automatically display the value of a bind variable created with VARIABLE, use the SET AUTOPRINT command.
    ON or OFF controls whether SQL*Plus automatically displays bind variables (referenced in a successful PL/SQL block or used in an EXECUTE command).

    Source: Oracle Documentation

    Friday, September 12, 2014

    How to solve ORA-27125: unable to create shared memory segment on AIX

    When starting an Oracle instance on a new AIX server, the following error may occur:

    ORA-27125: unable to create shared memory segment
    IBM AIX RISC System/6000 Error: 1: Not owner
    

    The situation is resolved by setting "capabilities" on the oracle operating system user, as follows:

    [root@server1] lsuser -a capabilities oracle
    oracle
    [root@tsu0emdb02] chuser capabilities=CAP_BYPASS_RAC_VMM,CAP_PROPAGATE oracle
    [root@tsu0emdb02] lsuser -a capabilities oracle
    oracle capabilities=CAP_BYPASS_RAC_VMM,CAP_PROPAGATE
    

    You can now start your instance:
    server1:testdb1>sqlplus / as sysdba
    
    SQL*Plus: Release 11.2.0.4.0 Production on Fri Sep 12 12:10:04 2014
    
    Copyright (c) 1982, 2013, Oracle.  All rights reserved.
    
    Connected to an idle instance.
    
    SQL> startup nomount
    ORACLE instance started.
    
    Total System Global Area 5344731136 bytes
    Fixed Size                  2255784 bytes
    Variable Size            1392510040 bytes
    Database Buffers         3942645760 bytes
    Redo Buffers                7319552 bytes
    SQL>
    

    Thursday, September 11, 2014

    What constitute "default auditing" under traditional auditing?

    From the Oracle Documentation:

    "When you use Database Configuration Assistant (DBCA) to create a new database, Oracle Database configures the database to audit the most commonly used security-relevant SQL statements and privileges"

    and

    "If you manually create a database, then you should run the secconf.sql script to apply the default audit settings to your database"

    Oracle Database audits the following privileges by default:

  • ALTER ANY PROCEDURE
  • CREATE ANY LIBRARY
  • DROP ANY TABLE
  • ALTER ANY TABLE
  • CREATE ANY PROCEDURE
  • DROP PROFILE
  • ALTER DATABASE
  • CREATE ANY TABLE
  • DROP USER
  • ALTER PROFILE
  • CREATE EXTERNAL JOB
  • EXEMPT ACCESS POLICY
  • ALTER SYSTEM
  • CREATE PUBLIC DATABASE LINK
  • GRANT ANY OBJECT PRIVILEGE
  • ALTER USER
  • CREATE SESSION
  • GRANT ANY PRIVILEGE
  • AUDIT SYSTEM
  • CREATE USER
  • GRANT ANY ROLE
  • CREATE ANY JOB
  • DROP ANY PROCEDURE

    Oracle Database audits the following SQL shortcuts by default:

  • ROLE
  • SYSTEM AUDIT
  • PUBLIC SYNONYM
  • DATABASE LINK
  • PROFILE
  • SYSTEM GRANT

    Remember that secconf.sql turns on audting regardless of your database using Unified Auditing or Traditional Auditing.

    How?

    When executed manually, the DBA is prompted for which type of auditing style that should be considered:
    sqlplus / as sysdba @secconf.sql
    
    Session altered.
    
    
    Profile altered.
    
    Do you wish to configure 11g style Audit Configuration OR
    Do you wish to configure 12c Unified Audit Policies?
    Enter RDBMS_11G for former or RDBMS_UNIAUD for latter
    Enter value for 1: RDBMS_11G
    old   7:   USER_CHOICE := '&1';
    new   7:   USER_CHOICE := 'RDBMS_11G';
    
    What I have found, is that if you intend to harden your Traditional Auditing policies by executing the script in a database where the Unified Auditing polices exist but is disabled, or a database running in "Mixed mode" auditing, the script will fail:
    DECLARE
    *
    ERROR at line 1:
    ORA-46358: Audit policy ORA_ACCOUNT_MGMT already exists.
    ORA-06512: at line 9
    
    A simple workaround in such a case is to simply comment out the code that is irrelevant to your desired type of auditing, and rerun the script.

    You can disable default auditing if you wish, see the section "Disabling and Enabling Default Audit Settings"

    To check whether or not default auditing has been actived, you can query the view DBA_PRIV_AUDIT_OPTS, which describes current system privileges being audited across the system and by user. If the column USERNAME is NULL, you have introduced system-wide auditing.
  • Tuesday, September 2, 2014

    How to convert stored outlines to use SQL Plan Baselines

    If you have been using stored outlines for plan stability in versions prior to Oracle 11g, you should migrate them to use SQL Plan Baselines instead. Stored outlines is, according to oracle, "a legacy technique for providing plan stability".

    My database had a number of stored outlines:

    SELECT OWNER, CATEGORY, USED, MIGRATED,COUNT(*) 
    FROM   DBA_OUTLINES
    GROUP BY OWNER,CATEGORY,USED,MIGRATED
    ORDER BY MIGRATED;
    
    OWNER CATEGORY USED MIGRATED COUNT(*)
    USER1 DEFAULT USED MIGRATED
    3
    USER2 DEFAULT USED MIGRATED
    1
    USER3 DEFAULT USED NOT-MIGRATED
    7
    USER1 DEFAULT USED NOT-MIGRATED
    7
    USER4 DEFAULT USED NOT-MIGRATED
    1
    USER2 DEFAULT USED NOT-MIGRATED
    36

    I created the following pl/sql to convert them to SQL Plan Baselines using the package DBMS_SPM.MIGRATE_STORED_OUTLINE:

    SET TRIMSPOOL ON
    SET LINES 200
    SET PAGES 200
    ALTER SESSION SET NLS_LANGUAGE='AMERICAN'; <-- to get English messages during execution
    SPOOL CONVERT_OUTLINES.LOG
    SET SERVEROUTPUT ON
    DECLARE
      L_CLOB            CLOB; -- will display the resulting report
    
      CURSOR C1 IS
        SELECT OWNER,NAME
        FROM DBA_OUTLINES
        WHERE MIGRATED = 'NOT-MIGRATED';
    
        C1_REC C1%ROWTYPE;
    
     BEGIN
        DBMS_OUTPUT.ENABLE( 1000000 );
    
        IF NOT C1%ISOPEN THEN
           OPEN C1;
        END IF;
     
         LOOP
           FETCH C1 INTO C1_REC;
           EXIT WHEN C1%NOTFOUND;
           DBMS_OUTPUT.PUT_LINE('Now converting: ' || C1_REC.OWNER || '.' || C1_REC.NAME);
           L_CLOB := DBMS_SPM.MIGRATE_STORED_OUTLINE( ATTRIBUTE_NAME=>'OUTLINE_NAME', ATTRIBUTE_VALUE=>C1_REC.NAME, FIXED=>'NO');
           DBMS_OUTPUT.PUT_LINE( L_CLOB );
         END LOOP;
        CLOSE C1;
    END;
    /
    EXIT
    

    The resulting log files shows that several of the stored outlines could not be converted:
    Now converting: USER2.SYS_OUTLINE_11021513055564321
    -------------------------------------------------------------------------------
    
                   Migrate Stored Outline to SQL Plan Baseline
    
    Report
    -------------------------------------------------------------------------------
    
    Summary:
    --------
    
    Number of stored outlines to be migrated: 1
    Stored outlines migrated successfully: 0
    Stored outlines failed to be migrated: 1
    
    Summary of Reasons for failure:
    -------------------------------
    
    Number of invalid stored outlines: 1
    
    Details on stored outlines not migrated or name changes during migration:
    -------------------------------------------------------------------------
    
    * Notes on name change:
    * New SQL plan baselines are assigned the same names as their original stored 
    * outlines. If a stored outline has the same name as an existing
    * SQL plan baseline, a system generated name is used for the new
    * SQL plan baseline.
    

    I then checked with the developers. It turned out that the outlines that didn't convert properly were remnants from the database when it was totally different laid out - the schemas had by now diverged and I could simply ignore these obsolete outlines.

    So the last step was simply to generate a drop-script for the non-migrated outlines and then execute these:
    SELECT 'DROP OUTLINE ' || NAME || ';'
    FROM DBA_OUTLINES
    WHERE MIGRATED = 'NOT-MIGRATED';
    

    Friday, August 29, 2014

    Login storm against database caused exhausted library cache

    One of our databases experienced massive contention in the shared pool, in form of wait events alerted as "library cache locks".

    The database was very small indeed, so my natural instinct was to throw some more memory at the virtual host, and rearrange the memory parameters.

    This turned out to be a misconception; the resources were sufficient for the instance to work properly.

    The problem was caused by an incorrect password configuration on the application server.

    What we could observe was:

  • A totally exhausted shared pool, caused by "library cache lock"
  • The SQL that seemed to be repeatedly executed was
    SELECT /*+ connect_by_filtering */
              privilege#, LEVEL
          FROM sysauth$
    CONNECT BY grantee# = PRIOR privilege# AND privilege# > 0
    START WITH grantee# = :1 AND privilege# > 0;
    
    
    SELECT privilege#
      FROM sysauth$
    WHERE (grantee# = :1 OR grantee# = 1) AND privilege# > 0;
    
  • The V$EVENT_NAME view showed that the wait event was accompanied by the additional information found in the columns parameter1 through parameter3, which turned out to be helpful further on:
    select  name, wait_class,parameter1,parameter2,parameter3
    from v$event_name
    where wait_class = 'Concurrency'
    and name = 'library cache lock';
    

    NAME WAIT_CLASS PARAMETER1 PARAMETER2 PARAMETER3
    library cache lock Concurrency handle address lock address 100*mode+namespace

    Further research showed that the problem was due to a built-in delay between failed login attempts in Oracle 11g:

    "The 'library cache lock' wait is seen due to the fact that the account status gets updated due to incorrect login.
    To prevent password guessing attack, there's a sleep() in the code when incorrect login attempts exceed count of 3.
    And because of this sleep() you see a wait on library cache, as the process is yet to release the lock."


  • In release 11.1.0.7, patch 7715339 was released to remove this delay.
  • In release 11.2.X, the DBA must set an event to remove the delay, as follows:

    alter system set events '28401 trace name context forever, level 1'; 
    

    According to Oracle, the purpose of the built-sleep is to make it harder to succeed in a "password guessing attack", particularly in cases where FAILED_LOGIN_ATTEMPTS is set to UNLIMITED. Oracle Development is pointing out that disabling the sleep-function is not recommended. A better solution is to set the FAILED_LOGIN_ATTEMPTS to a reasonable value.
    When the number of failed login attempts for a session hits the limit, the account will be locked. Subsequent logon attempts with incorrect password will then be rejected immediately without any contention in the library cache.

    See Bug 15882590 : 'LIBRARY CACHE LOCK' DURING WRONG PASSWORD LOGON ATTEMPTS on My Oracle Support (MOS) for further information.