26aiCDB/PDBData Guard

Oracle Data Guard Broker PL/SQL API Limitations with DGPDB Switchover

By August 28, 2026No Comments8 min read

Oracle Data Guard Broker provides DGMGRL as its primary command-line management interface, while the DBMS_DG PL/SQL package enables several Data Guard Broker operations to be controlled programmatically from scripts and custom tools. https://docs.oracle.com/en/database/oracle/oracle-database/26/dgbkr/DBMS_DG.html

With Data Guard protection available at the individual Pluggable Database level, commonly referred to as DGPDB, an interesting automation question arises: Can we perform an individual DGPDB switchover using the DBMS_DG PL/SQL API instead of DGMGRL?

I tested this behavior in an Oracle AI Database 26ai DGPDB environment. The results demonstrate an important distinction between the database-level DBMS_DG switchover API and the PDB-level switchover operation provided by Data Guard Broker.

DGPDB Environment

The test environment consists of two primary CDBs participating in separate Broker configurations, with Data Guard protection configured between individual PDBs.

Source CDB       : ORCLRUH
Source PDB       : RUH_PDB
Target CDB       : ORCLJED
Target PDB       : JED_PDB

This architecture is important because DGPDB differs from traditional database-level Data Guard. Oracle documents that DGPDB protection uses two primary databases, with the source PDB protected by a target PDB in another CDB.

The source PDB was open in READ WRITE mode.

SQL> show pdbs

    CON_ID CON_NAME                       OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
         2 PDB$SEED                       READ ONLY  NO
         3 RUH_PDB                        READ WRITE NO
SQL>

The objective was to determine whether DBMS_DG could perform a role transition specifically between RUH_PDB and JED_PDB without performing a role transition of the complete CDB.

Testing DBMS_DG.SWITCHOVER from CDB$ROOT

The first test was performed while connected to CDB$ROOT as SYSDBA.

SQL>   conn / as sysdba
Connected.
set serveroutput on;
declare
  v_severity binary_integer;
  v_retcode  binary_integer;
begin
  dbms_output.put_line('initiating dynamic database role transition to orcljed...');
  execute immediate
    'begin :1 := dbms_dg.switchover(db_name => ''orcljed'', severity => :2); end;'
    using out v_retcode, out v_severity;
  dbms_output.put_line('broker execution return code: ' || v_retcode);
  dbms_output.put_line('broker validation severity state: ' || v_severity);
exception
  when others then
    dbms_output.put_line('programmatic switchover failed with error: ' || sqlerrm);
end;
/
Connected.
SQL> 
initiating dynamic database role transition to orcljed...
broker execution return code: 16617
broker validation severity state: 16501
PL/SQL procedure successfully completed.
SQL>
SQL> show pdbs

    CON_ID CON_NAME                       OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
         2 PDB$SEED                       READ ONLY  NO
         3 RUH_PDB                        READ WRITE NO
SQL>

The PL/SQL call returned Broker status information, but no DGPDB role transition occurred. RUH_PDB remained READ WRITE on the source.

Checking the Available DBMS_DG Switchover Procedures

The next step was to verify exactly which switchover procedures are exposed by DBMS_DG in the installed environment.

SQL> set lines 200
col procedure_name format a45
select procedure_name
from dba_procedures
where owner='SYS'
and object_name='DBMS_DG'
and procedure_name like '%SWITCH%'
order by procedure_name;
PROCEDURE_NAME
---------------------------------------------
SWITCHOVER
SQL>

The result confirms that SWITCHOVER is the available switchover operation in DBMS_DG.

More importantly for this test, there is no separate PDB-specific switchover procedure exposed by the package. This leaves another possibility worth testing: perhaps executing DBMS_DG.SWITCHOVER while the current session is connected to the protected PDB causes Oracle to scope the operation to that PDB.

Testing from Within the Protected PDB

The source PDB was first confirmed to be open READ WRITE.

SQL> show pdbs

    CON_ID CON_NAME                       OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
         2 PDB$SEED                       READ ONLY  NO
         3 RUH_PDB                        READ WRITE NO
SQL>

The session was then changed to RUH_PDB. Before attempting the switchover, I verified whether DBMS_DG.SWITCHOVER was visible while connected to the PDB.

SQL> set serveroutput on
SQL> alter session set container=RUH_PDB;
set serveroutput on
declare
  l_owner     varchar2(30);
  l_name      varchar2(30);
  l_line      varchar2(4000);
begin
  dbms_output.put_line('Container      : ' || sys_context('USERENV','CON_NAME'));
  select owner, object_name
  into l_owner, l_name
  from dba_procedures
  where owner='SYS'
  and object_name='DBMS_DG'
  and procedure_name='SWITCHOVER'
  and rownum=1;
  dbms_output.put_line('Procedure found: ' || l_owner || '.' || l_name || '.SWITCHOVER');
  dbms_output.put_line('No switchover executed.');
exception
  when others then
    dbms_output.put_line('ERROR: ' || sqlerrm);
end;
/
Session altered.
SQL> 
Container      : RUH_PDB
Procedure found: SYS.DBMS_DG.SWITCHOVER
No switchover executed.
PL/SQL procedure successfully completed.
SQL>

This confirms that DBMS_DG.SWITCHOVER is visible while the current container is RUH_PDB. The next step was to determine whether it can actually execute from that container.

Executing DBMS_DG.SWITCHOVER from RUH_PDB

The database-level switchover API was executed while the current container was RUH_PDB.

SQL> declare
  l_severity binary_integer;
  l_status   binary_integer;
begin
  2    3    4    5    dbms_output.put_line('Current container: ' || sys_context('USERENV','CON_NAME'));
  dbms_output.put_line('Calling DBMS_DG.SWITCHOVER to ORCLJED...');
  l_status := dbms_dg.switchover(
                db_name  => 'ORCLJED',
                severity => l_severity
              );
  dbms_output.put_line('Return status : ' || l_status);
  dbms_output.put_line('Severity      : ' || l_severity);
exception
  when others then
    dbms_output.put_line('ERROR CODE : ' || sqlcode);
    dbms_output.put_line('ERROR      : ' || sqlerrm);
end;
/  
Current container: RUH_PDB
Calling DBMS_DG.SWITCHOVER to ORCLJED...
ERROR CODE : -65040
ERROR      : ORA-65040: Operation is not allowed from within a pluggable database.
PL/SQL procedure successfully completed.
SQL>

This result clearly establishes the limitation:

ORA-65040: Operation is not allowed from within a pluggable database.

The procedure is visible from the PDB, but the switchover operation itself cannot be executed from within the PDB. Therefore, changing the current container to RUH_PDB does not make the database-level DBMS_DG.SWITCHOVER operation PDB-aware.

What the Testing Confirms

The testing highlights a clear separation between database-level and DGPDB-level role transitions.

TestResult
DBMS_DG.SWITCHOVER from CDB$ROOTDatabase-level operation
Target supplied to DBMS_DG.SWITCHOVERTarget database
DBMS_DG switchover procedures availableSWITCHOVER
Separate PDB switchover API foundNo
DBMS_DG.SWITCHOVER visible from RUH_PDBYes
DBMS_DG.SWITCHOVER executable from RUH_PDBNo
Error returnedORA-65040
DGPDB switchover interfaceData Guard Broker/DGMGRL

The key takeaway is that connecting to a PDB does not change the scope of DBMS_DG.SWITCHOVER.

The database-level API also does not provide the combination of target PDB and target database that is required to uniquely identify a DGPDB switchover target.

How DGPDB Switchover Is Different

Oracle defines a PDB switchover as a role reversal between a source PDB and its designated target PDB. During the operation, Broker validates both PDBs, ensures that the target is recovering the source redo stream, closes the source PDB, converts the source to the standby role, converts the target to the primary role, opens the new source PDB, and starts recovery on the former source.

This is different from a traditional database-level switchover, where the roles of the primary and standby databases themselves are reversed.

For DGPDB, Broker therefore needs to know both:

Target PDB       : JED_PDB
Target Database  : ORCLJED

That information is represented directly in the DGMGRL syntax.

Performing the DGPDB Switchover

Oracle specifically documents DGMGRL commands for performing PDB switchovers.

For this environment, the role transition is performed using:

DGMGRL> SWITCHOVER TO PLUGGABLE DATABASE JED_PDB AT ORCLJED;

Here:

JED_PDB  = Target PDB that will assume the primary/source role
ORCLJED  = Target database containing JED_PDB

This is exactly the information that cannot be expressed through the database-level DBMS_DG.SWITCHOVER interface.

Oracle’s documented syntax is:

DGMGRL> SWITCHOVER TO PLUGGABLE DATABASE <pdb_name> AT <target_db_unique_name>;

The specified PDB must exist in the target database and must already be configured as a DGPDB.

During the switchover, Data Guard Broker manages the required role transition activities and ultimately makes the target PDB the new source PDB.

Automation Consideration

DBMS_DG remains valuable for programmatically managing and monitoring many Data Guard Broker operations. Oracle specifically describes these APIs as a mechanism for controlling Broker configurations from scripts and batch programs.

However, the tests demonstrate that the database-level SWITCHOVER API cannot simply be reused for an individual DGPDB switchover.

For automated DGPDB role transitions, DGMGRL can instead be incorporated into shell scripts or other orchestration frameworks while using the PDB-specific Broker command:

DGMGRL> SWITCHOVER TO PLUGGABLE DATABASE JED_PDB AT ORCLJED;

Conclusion

DBMS_DG.SWITCHOVER operates at the database level and cannot be executed from within a PDB, as confirmed by ORA-65040. For an individual DGPDB switchover, Data Guard Broker through the PDB-specific DGMGRL command remains the appropriate interface.

Leave a Reply