How to extract user DDL and all privileges of a user in oracle

We often require to extract information such as User DDL and all privileges granted including roles, system and object privileges, tablespace quota etc. Using the following method we can extract it easily.

Create a .sql file and paste the following code inside.

Note:- While executing this sql make sure to enter the username in UPPERCASE.

vi info.sql

-- Connect to target database and execute with a user that has DBA privileges

 

-- Example for user "CRPDTA" - Make sure to put the username in uppercase.

 

SET LONGCHUNKSIZE 20000 PAGESIZE 0 FEEDBACK OFF VERIFY OFF TRIMPOOL ON

COLUMN Extracted_DDL FORMAT A1000

 

EXEC DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.SESSION_TRANSFORM, 'PRETTY', TRUE);

EXEC DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.SESSION_TRANSFORM, 'SQLTERMINATOR', TRUE);

 

UNDEFINE User_in_Uppercase;

 

SET LINESIZE 1000

SET LONG 2000000000

 

SELECT

    (CASE

        WHEN (

            (SELECT COUNT(*)

             FROM DBA_USERS

             WHERE USERNAME = '&&User_in_Uppercase' AND PROFILE <> 'DEFAULT') > 0

        ) THEN

            CHR(10) || ' -- Note: Profile' || (SELECT DBMS_METADATA.GET_DDL('PROFILE', U.PROFILE) AS DDL

                                               FROM DBA_USERS U

                                               WHERE U.USERNAME = '&User_in_Uppercase')

        ELSE

            TO_CLOB(CHR(10) || ' -- Note: Default profile, no need to create!')

    END)

FROM DUAL

UNION ALL

SELECT

    (CASE

        WHEN (

            (SELECT COUNT(*)

             FROM DBA_USERS

             WHERE USERNAME = '&User_in_Uppercase') > 0

        ) THEN

            ' -- Note: Create user statement' || DBMS_METADATA.GET_DDL('USER', '&User_in_Uppercase')

        ELSE

            TO_CLOB(CHR(10) || ' -- Note: User not found!')

    END) Extracted_DDL

FROM DUAL

UNION ALL

SELECT

    (CASE

        WHEN (

            (SELECT COUNT(*)

             FROM DBA_TS_QUOTAS

             WHERE USERNAME = '&User_in_Uppercase') > 0

        ) THEN

            ' -- Note: TBS quota' || DBMS_METADATA.GET_GRANTED_DDL('TABLESPACE_QUOTA', '&User_in_Uppercase')

        ELSE

            TO_CLOB(CHR(10) || ' -- Note: No TS Quotas found!')

    END)

FROM DUAL

UNION ALL

SELECT

    (CASE

        WHEN (

            (SELECT COUNT(*)

             FROM DBA_ROLE_PRIVS

             WHERE GRANTEE = '&User_in_Uppercase') > 0

        ) THEN

            ' -- Note: Roles' || DBMS_METADATA.GET_GRANTED_DDL('ROLE_GRANT', '&User_in_Uppercase')

        ELSE

            TO_CLOB(CHR(10) || ' -- Note: No granted Roles found!')

    END)

FROM DUAL

UNION ALL

SELECT

    (CASE

        WHEN (

            (SELECT COUNT(*)

             FROM V$PWFILE_USERS

             WHERE USERNAME = '&User_in_Uppercase' AND SYSDBA = 'TRUE') > 0

        ) THEN

            ' -- Note: sysdba' || CHR(10) || TO_CLOB(' GRANT SYSDBA TO ' || '"' || '&User_in_Uppercase' || '"' || ';')

        ELSE

            TO_CLOB(CHR(10) || ' -- Note: No sysdba administrative Privilege found!')

    END)

FROM DUAL

UNION ALL

SELECT

    (CASE

        WHEN (

            (SELECT COUNT(*)

             FROM DBA_SYS_PRIVS

             WHERE GRANTEE = '&User_in_Uppercase') > 0

        ) THEN

            ' -- Note: System Privileges' || DBMS_METADATA.GET_GRANTED_DDL('SYSTEM_GRANT', '&User_in_Uppercase')

        ELSE

            TO_CLOB(CHR(10) || ' -- Note: No System Privileges found!')

    END)

FROM DUAL

UNION ALL

SELECT

    (CASE

        WHEN (

            (SELECT COUNT(*)

             FROM DBA_TAB_PRIVS

             WHERE GRANTEE = '&User_in_Uppercase') > 0

        ) THEN

            ' -- Note: Object Privileges' || DBMS_METADATA.GET_GRANTED_DDL('OBJECT_GRANT', '&User_in_Uppercase')

        ELSE

            TO_CLOB(CHR(10) || ' -- Note: No Object Privileges found!')

    END)

FROM DUAL

/

 

Output:-

Login into database and run the sql we created above.. We used username as “PY920”

sqlplus / as sysdba

SQL> @info.sql

Enter value for user_in_uppercase: PY920

 

 -- Note: Profile

   CREATE PROFILE "UNLIM_LOG"

    LIMIT

         COMPOSITE_LIMIT UNLIMITED

         SESSIONS_PER_USER UNLIMITED

         CPU_PER_SESSION UNLIMITED

         CPU_PER_CALL UNLIMITED

         LOGICAL_READS_PER_SESSION UNLIMITED

         LOGICAL_READS_PER_CALL UNLIMITED

         IDLE_TIME UNLIMITED

         CONNECT_TIME UNLIMITED

         PRIVATE_SGA UNLIMITED

         FAILED_LOGIN_ATTEMPTS UNLIMITED

         PASSWORD_LIFE_TIME UNLIMITED

         PASSWORD_REUSE_TIME UNLIMITED

         PASSWORD_REUSE_MAX UNLIMITED

         PASSWORD_VERIFY_FUNCTION DEFAULT

         PASSWORD_LOCK_TIME UNLIMITED

         PASSWORD_GRACE_TIME UNLIMITED

         INACTIVE_ACCOUNT_TIME DEFAULT

         PASSWORD_ROLLOVER_TIME DEFAULT ;

 

 -- Note: Create user statement

   CREATE USER "PY920" IDENTIFIED BY VALUES 'S:E927BDEC46440F4264941D55A483B1C07A522B852D94203349093C5B2F2D;T:5FC638A2DA78087F85E7BABF9EA95404BD400DC6923181FE420BC91A8A11C6CD4B5D95103E1FB27E01981266C7B3F43C9AE5851EE4AFFC7BDC6066E63598D80C51295AC44FAD0651B66B72A4C2E0E639'

      DEFAULT TABLESPACE "PY920T"

      TEMPORARY TABLESPACE "TEMP2"

      PROFILE "UNLIM_LOG";

 ALTER USER "PY920" LOCAL TEMPORARY TABLESPACE "TEMP2";

 

 -- Note: TBS quota

  DECLARE

  TEMP_COUNT NUMBER;

  SQLSTR VARCHAR2(200);

BEGIN

  SQLSTR := 'ALTER USER "PY920" QUOTA UNLIMITED ON "PY920I"';

  EXECUTE IMMEDIATE SQLSTR;

EXCEPTION

  WHEN OTHERS THEN

    IF SQLCODE = -30041 THEN

      SQLSTR := 'SELECT COUNT(*) FROM USER_TABLESPACES

              WHERE TABLESPACE_NAME = ''PY920I'' AND CONTENTS = ''TEMPORARY''';

      EXECUTE IMMEDIATE SQLSTR INTO TEMP_COUNT;

      IF TEMP_COUNT = 1 THEN RETURN;

      ELSE RAISE;

      END IF;

    ELSE

      RAISE;

    END IF;

END;

/

  DECLARE

  TEMP_COUNT NUMBER;

  SQLSTR VARCHAR2(200);

BEGIN

  SQLSTR := 'ALTER USER "PY920" QUOTA UNLIMITED ON "PY920T"';

  EXECUTE IMMEDIATE SQLSTR;

EXCEPTION

  WHEN OTHERS THEN

    IF SQLCODE = -30041 THEN

      SQLSTR := 'SELECT COUNT(*) FROM USER_TABLESPACES

              WHERE TABLESPACE_NAME = ''PY920T'' AND CONTENTS = ''TEMPORARY''';

      EXECUTE IMMEDIATE SQLSTR INTO TEMP_COUNT;

      IF TEMP_COUNT = 1 THEN RETURN;

      ELSE RAISE;

      END IF;

    ELSE

      RAISE;

    END IF;

END;

/

 

 -- Note: Roles

   GRANT "JDEUSER" TO "PY920";

   GRANT "JDE_ROLE" TO "PY920";

 

 

 -- Note: No sysdba administrative Privilege found!

 

 

 -- Note: No System Privileges found!

 

 

 -- Note: No Object Privileges found!

 

SQL>

 


Steps to Clone A Pluggable Database From Existing PDB

 

Steps to Clone A Pluggable Database From Existing PDB

 

So, I had a requirement for a customer where I had to clone a PDB from existing PDB on same CDB . I followed the following steps to do this.

 

Step 1.

Put the PDB in read only mode

SQL> select name,open_mode from v$pdbs;

 

NAME OPEN_MODE

------------------------------ ----------

PDB$SEED READ ONLY

DEV READ WRITE

 

 

SQL> alter session set container=DEV;
 
Session altered.
 
SQL> select file_name from dba_data_files;
 
FILE_NAME
--------------------------------------------------------------------------------
/u01/app/oracle/oradata/nonprod/dev/system01.dbf
/u01/app/oracle/oradata/nonprod/dev/sysaux01.dbf
/u01/app/oracle/oradata/nonprod/dev/users01.dbf
 

 

SQL> show con_name
 
CON_NAME
------------------------------
DEV
 
SQL> shu immediate;
Pluggable Database closed.
 
SQL> startup open read only
Pluggable Database opened.

 

 

 

Step 2.

Connect to the CDB and initiate PDB clone:

 

Set Oracle SID as CDB SID

[oracle@server1]$export ORACLE_SID=NONPROD

[oracle@server1]$sqlplus / as sysdba

SQL> show con_name
 
CON_NAME
------------------------------
CDB$ROOT

 

-- Clone pluggable

 

 

SQL> create pluggable database DEVCLONE from DEV FILE_NAME_CONVERT=('/u01/app/oracle/oradata/nonprod/dev','/u01/app/oracle/oradata/nonprod/devclone');

Pluggable database created.

 

 

 

Step 3:

Start the new cloned PDB In read write mode

SQL> select name,open_mode from v$pdbs;
 
NAME OPEN_MODE
------------------------------ ----------
PDB$SEED READ ONLY
DEV READ ONLY
DEVCLONE MOUNTED
 
SQL> alter session set CONTAINER=DEV;
 
Session altered.
 
SQL> shutdown immediate;
Pluggable Database closed.
SQL> startup
Pluggable Database opened.
SQL> show con_name
DEV

 

 

 

 

Step4:-

start the new cloned PDB( DEVCLONE)

SQL> alter session set container=DEVCLONE;
 
Session altered.
SQL> SHU IMMEDIATE
 
SQL> startup
Pluggable Database opened.
 
 
SQL> conn sys/syspassword@NONPROD as sysdba
Connected.
SQL> select name,open_mode from v$pdbs;
 
NAME OPEN_MODE
------------------------------ ----------
PDB$SEED READ ONLY
DEV READ WRITE
DEVCLONE READ WRITE

 

 

 

Oracle datapump error ORA-39077: unable to subscribe agent KUPC$A_1_083325450472000

Oracle datapump error ORA-39077: unable to subscribe agent KUPC$A_1_083325450472000

 

During import we faced following error.

Error Details:-


D:\oracle\product\19.3.0\dbhome_1\bin>impdp HOSPITAL/HOSPITAL@ORCL dumpfile=EXP_HOSPITAL_20231113140110_A.DMP logfile=IMP_HOSPITAL_20231113140110_A.LOG directory=dumps

 

Import: Release 19.0.0.0.0 - Production on Mon Nov 13 16:59:16 2023

Version 19.13.0.0.0

 

Copyright (c) 1982, 2021, Oracle and/or its affiliates.  All rights reserved.

 

Connected to: Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production

ORA-31626: job does not exist

ORA-31638: cannot attach to job SYS_IMPORT_FULL_01 for user HOSPITAL

ORA-06512: at "SYS.KUPV$FT", line 1142

ORA-06512: at "SYS.KUPV$FT", line 1744

ORA-06512: at "SYS.DBMS_SYS_ERROR", line 95

ORA-06512: at "SYS.KUPV$FT_INT", line 498

ORA-39077: unable to subscribe agent KUPC$A_1_165917326000000 to queue "KUPC$C_1_20231113165917_0"

ORA-06512: at "SYS.DBMS_SYS_ERROR", line 95

ORA-06512: at "SYS.KUPC$QUE_INT", line 294

ORA-00972: identifier is too long

ORA-06512: at "SYS.DBMS_AQADM_SYS", line 9306

ORA-06512: at "SYS.DBMS_PRVTAQIS", line 1873

ORA-06512: at "SYS.DBMS_PRVTAQIS", line 3802

ORA-06512: at "SYS.DBMS_RULE_ADM", line 296

ORA-06512: at "SYS.DBMS_RULEADM_INTERNAL", line 106

ORA-24000: invalid value "SYS"."KUPC$C_1_20231113165917_0$10471", RULE SET should be of the form [SCHEMA.]NAME

ORA-00972: identifier is too long

ORA-06512: at "SYS.DBMS_RULEADM_INTERNAL", line 109

ORA-06512: at "SYS.DBMS_RULEADM_INTERNAL", line 97

ORA-06512: at "SYS.DBMS_RULE_ADM", line 290

ORA-06512: at "SYS.DBMS_PRVTAQIS", line 3757

ORA-06512: at "SYS.DBMS_PRVTAQIS", line 3709

ORA-06512: at "SYS.DBMS_PRVTAQIS", line 1756

ORA-06512: at "SYS.DBMS_PRVTAQIS", line 1516

ORA-06512: at "SYS.DBMS_AQADM_SYS", line 9900

ORA-06512: at "SYS.DBMS_AQADM_SYS", line 9269

ORA-06512: at "SYS.DBMS_AQADM", line 881

ORA-06512: at "SYS.KUPC$QUE_INT", line 267

ORA-06512: at "SYS.KUPC$QUE_INT", line 1360

ORA-06512: at line 1

ORA-06512: at "SYS.KUPC$QUEUE_INT", line 65

ORA-06512: at "SYS.KUPV$FT_INT", line 465

ORA-06512: at "SYS.KUPV$FT", line 1664



Cause:-

Once the sequence SYS.AQ$_KUPC$DATAPUMP_QUETAB_1_N exceeds 10000, the name of a rule set then exceeds 30 characters, which should not be a problem any more with 19c version.

The max identifier length with DB compatibility set to < 12.2  is  30
The max identifier length with DB compatibility set to >= 12.2  is  128

The issue in this case was caused due to compatible setting 11.2.0.4.0, in which case the name of a rule set then cannot exceed 30 characters.

 

Solution:-

 

Since our database was of version 19c which was upgraded from 11.2.0.4 but the compatible was still set to “11.2.0.4.0”. Because of this the issue was present.

After changing the compatible parameter to “19.0.0” it was resolved

 

SQL> alter system set compatible=’19.0.0’ scope=spfile;


batch script to send email notification once if any service goes down and sends mail once service is up

Hi Everyone,

Recently I came across an issue where oracle service on windows was getting stopped due to some reason. Since customer was not using any monitoring tool, it was very hard to track when the service was going down.

To mitigate the problem , I wrote a batch script which will monitor oracleservice and listener service on windows . The script will send a mail once notifying service has gone down and once service comes back it will send another notification on email with service is running message.

Save the following script in .bat format and schedule it as per your requirement in task scheduler.

@echo off

setlocal enabledelayedexpansion

set my_date=%date%

set my_time=%TIME%

set my_hours=%my_time:~0,2%

set my_minutes=%my_time:~3,2%

set my_seconds=%my_time:~6,2%

 

rem Configure email settings

 

set TO_EMAIL=soumya.das@email.com

set FROM_EMAIL=noreply@alerts.com

set SMTP_SERVER=smtp.gmail.com

set SMTP_PORT=587 

set SMTP_USER=noreply@alerts.com

set SMTP_PASSWORD=Password

set SUBJECT="Service Monitor Alert"

 

rem List of services to monitor (add more as needed)

set "SERVICES=OracleServiceORCL OracleOraDB19Home1TNSListener"

 

rem Create a temporary file to store service status

set STATUS_FILE=status.txt

 

rem Loop through the services and check their status using PowerShell

for %%s in (%SERVICES%) do (

    sc query "%%s" | find "STATE" | find "RUNNING" >nul

    if errorlevel 1 (

        echo %%s service is not running.

        if not exist !STATUS_FILE! (

            echo Sending email notification.

            powershell -command "Send-MailMessage -From '%FROM_EMAIL%' -To '%TO_EMAIL%' -Subject '%SUBJECT%' -Body 'The %%s service is not running.' -SmtpServer '%SMTP_SERVER%' -Port %SMTP_PORT% -UseSsl -Credential (New-Object PSCredential('%SMTP_USER%', (ConvertTo-SecureString '%SMTP_PASSWORD%' -AsPlainText -Force)))"

            rem Create the status file to indicate that an alert has been sent

            echo DOWN > !STATUS_FILE!

        )

    ) else (

        echo %%s service is running.

        if exist !STATUS_FILE! (

            echo Sending email notification.

            powershell -command "Send-MailMessage -From '%FROM_EMAIL%' -To '%TO_EMAIL%' -Subject 'Service Monitor Alert' -Body 'The %%s service is now running.' -SmtpServer '%SMTP_SERVER%' -Port %SMTP_PORT% -UseSsl -Credential (New-Object PSCredential('%SMTP_USER%', (ConvertTo-SecureString '%SMTP_PASSWORD%' -AsPlainText -Force)))"

            rem Delete the status file to indicate that the service is running

            del !STATUS_FILE!

        )

    )

)

 

endlocal


Shell script to convert physical standby database into snapshot standby and vice versa

 

Today I will show a scenario where a customer had a requirement to refresh their snapshot standby database. The setup was 1 primary database and 2 physical standby databases among which one standby database was always kept in physical standby mode but the other one was used by the developer and a daily refresh was the requirement.

Since they wanted to convert snapshot standby into physical standby for sync and later convert it back to snapshot standby I prepared two shell script to perform the entire activity.

 

·       Shell script to convert physical standby database into snapshot standby database

#!/bin/bash


 # Set environment variables

export ORACLE_HOME=/u01/oracle/19.3.0

export ORACLE_SID=PROD

export PATH=$ORACLE_HOME/bin:$PATH

 

# Define database names

PRIMARY_DB_NAME=PROD

STANDBY_DB_NAME=SBDB

 

# Define log file path

rm $LOG_FILE

LOG_FILE=/u01/snapshot_convert_logfile.log

 

# Define maximum number of retries

MAX_RETRIES=2

 

# Function to log messages to log file

log() {

  echo "$(date +'%Y-%m-%d %H:%M:%S') $1" >> $LOG_FILE

}

 

# Function to perform conversion

perform_conversion() {

  log "Performing conversion of $STANDBY_DB_NAME to snapshot standby..."

  dgmgrl <<EOF

  connect /

  convert database $STANDBY_DB_NAME to snapshot standby;

EOF

} >> $LOG_FILE

# Retry loop

retries=0

while [ $retries -lt $MAX_RETRIES ]; do

  perform_conversion

  if grep -q "ORA-" $LOG_FILE; then

    log "Error occurred during conversion. Retrying..."

    ((retries++))

    sleep 5

  else

    log "Conversion completed successfully. Standby database is now a snapshot standby."

    break

  fi

done

 

# Check for maximum retries

if [ $retries -eq $MAX_RETRIES ]; then

  log "Maximum retries reached. Conversion failed. Please check the log for details."

fi

 

 

·       Shell script to convert snapshot standby database into physical standby database

#!/bin/bash

 

# Set environment variables

export ORACLE_HOME=/u01/oracle/19.3.0

export ORACLE_SID=PROD

export PATH=$ORACLE_HOME/bin:$PATH

 

# Define database names

PRIMARY_DB_NAME=PROD

STANDBY_DB_NAME=SBDB

 

# Define log file path

rm $LOG_FILE

LOG_FILE=/u01/physical_convert_logfile.log

 

# Define maximum number of retries

MAX_RETRIES=2

 

# Function to log messages to log file

log() {

  echo "$(date +'%Y-%m-%d %H:%M:%S') $1" >> $LOG_FILE

}

 

# Function to perform conversion

perform_conversion() {

  log "Performing conversion of $STANDBY_DB_NAME to physical standby..."

dgmgrl sys/Prodpassword@prod<<EOF

convert database $STANDBY_DB_NAME to physical standby;

EOF

} >> $LOG_FILE

# Retry loop

retries=0

while [ $retries -lt $MAX_RETRIES ]; do

  perform_conversion

  if grep -q "ORA-" $LOG_FILE; then

    log "Error occurred during conversion. Retrying..."

    ((retries++))

    sleep 5

  else

    log "Conversion completed successfully. Standby database is now a physical standby."

    break

  fi

done

 

# Check for maximum retries

if [ $retries -eq $MAX_RETRIES ]; then

  log "Maximum retries reached. Conversion failed. Please check the log for details."

fi

 

Once the snapshot standby is converted to physical standby, give it time to synchronize with primary database.