Oracle has introduced multi tenant architecture with the release of Oracle database 12c (12.1.0.1). In a multi tenant Oracle database, we have a ROOT container database (CDB$ROOT), a SEED database (PDB$SEED) and the potential to have a number of pluggable databases (PDBs).
The ROOT (CDB$ROOT) is the parent container which hosts the SEED (PDB$SEED) and other pluggable databases. SEED is a READ-ONLY pluggable database and serves as a template, which is used to create new pluggable database (PDB) within a ROOT (CDB$ROOT) container.
The SEED (PDB$SEED) template PDB consists SYSTEM, SYSAUX and optionally TEMP and USER tablespaces as well as the default set of schemas. However, it may be desired by an organization to have certain additional tablespaces and or schemas to be available in the SEED template to meet the organization standards.
In this post, I will try to present a trick with a quick demonstration that you can use to customize the READ-ONLY seed template pluggable database and meet the required organizational standards for creating pluggable databases.
Lets say XYZ is an organization and has a requirement to have a database schema with name INFRA_USER to be available whenever a new pluggable database is created. This new schema must have the tablespace AUDIT_DATA as its default tablespace. Further, each pluggable database should have a tablespace called USER_DATA, which will serve as the default tablespace for users within the PDB.
Considering the given requirement, let’s check if we can modify the seed (pdb$seed) pluggable database to include the additional standards in to the template. In the following example, I have a container database ORPCDB1 with only the SEED template pluggable database.
---// ---// Container database with only pdb$seed template PDB //--- ---// SQL> select name,cdb from v$database; NAME CDB --------------- --- ORPCDB1 YES SQL> SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO SQL>
Let’s switch to the seed template PDB and try to accommodate the additional requirements.
---// ---// switch to pdb$seed template PDB //--- ---// SQL> alter session set container=pdb$seed; Session altered. SQL> show con_name; CON_NAME ------------------------------ PDB$SEED ---// ---// current set of tablespaces in the pdb$seed template PDB //--- ---// SQL> select tablespace_name from dba_tablespaces; TABLESPACE_NAME --------------- SYSTEM SYSAUX TEMP
Let’s try to add the additional tablespace AUDIT_DATA data as per our requirement in to the SEED (pdb$seed) template PDB.
---// ---// creating additional tablespace wihin pdb$seed template PDB //--- ---// SQL> create tablespace AUDIT_DATA datafile '/oradata/orpcdb1/pdbseed/audit_data01.dbf' size 200M; create tablespace AUDIT_DATA datafile '/oradata/orpcdb1/pdbseed/audit_data01.dbf' size 200M * ERROR at line 1: ORA-00604: error occurred at recursive SQL level 1 ORA-16000: database or pluggable database open for read-only access
As we can see, we are not allowed to create additional tablespace within pdb$seed as the seed database is in READ-ONLY mode. Let’s check if we can open the pdb$seed PDB in READ-WRITE mode. But before that we need to close the pdb$seed template PDB. Let’s do that.
---// ---// trying to close seed pluggable database //--- ---// SQL> alter pluggable database "pdb$seed" close; alter pluggable database "pdb$seed" close * ERROR at line 1: ORA-65017: seed pluggable database may not be dropped or altered
We are not even allowed to close the SEED pluggable database. Here comes the trick in picture. Oracle has a undocumented session level parameter called _oracle_script, which can be set to TRUE for operating on the SEED pluggable database pdb$seed.
---// ---// setting _oracle_script to TRUE to operate on pdb$seed //--- ---// SQL> show con_name CON_NAME ------------------------------ PDB$SEED SQL> select name,open_mode from v$pdbs; NAME OPEN_MODE --------------- ---------- PDB$SEED READ ONLY SQL> alter session set "_oracle_script"=true; Session altered. ---// ---// restart the pdb$seed to open in READ-WRITE mode //--- ---// SQL> shut immediate Pluggable Database closed. SQL> startup Pluggable Database opened. SQL> select name,open_mode from v$pdbs; NAME OPEN_MODE --------------- ---------- PDB$SEED READ WRITE
Now, the SEED pluggable database (pdb$seed) is in READ-WRITE mode (courtesy to the _oracle_script parameter). We can now customize the SEED pluggable database according to our requirement as shown below.
---// ---// creating additional tablespace within pdb$seed //--- ---// SQL> show con_name CON_NAME ------------------------------ PDB$SEED SQL> create tablespace AUDIT_DATA datafile '/oradata/orpcdb1/pdbseed/audit_data01.dbf' size 200M; Tablespace created. SQL> create tablespace USER_DATA datafile '/oradata/orpcdb1/pdbseed/user_data01.dbf' size 200M; Tablespace created. SQL> alter database default tablespace USER_DATA; Database altered. ---// ---// creating additional local user within pdb$seed //--- ---// SQL> create user infra_user identified by temp123 default tablespace AUDIT_DATA password expire; User created. ---// ---// validating the customization for pdb$seed //--- ---// SQL> select tablespace_name from dba_tablespaces order by tablespace_name; TABLESPACE_NAME --------------- AUDIT_DATA SYSAUX SYSTEM TEMP USER_DATA SQL> select username,default_tablespace,account_status 2 from dba_users where username='INFRA_USER'; USERNAME DEFAULT_TABLESPACE ACCOUNT_STATUS -------------------- ------------------------------ -------------------------------- INFRA_USER USER_DATA EXPIRED
We are now done with the customization for SEED pluggable database (pdb$seed). However, our seed database is still in READ-WRITE mode and we must revert it to its original READ-ONLY state to prevent any harm to the SEED pluggable database.
We can do that by shutting down the pdb$seed and opening it in READ-ONLY mode as shown below. We must also ensure that the session level parameter _oracle_script is set to FALSE once we revert the seed pluggable database to its original state. However, if we are terminating our current session that wouldn’t be necessary.
---// ---// closing pdb$seed //--- ---// SQL> shut immediate Pluggable Database closed. ---// ---// opening pdb$seed in READ-ONLY mode //--- ---// SQL> startup open read only Pluggable Database opened. ---// ---// validating pdb$seed state //--- ---// SQL> select name,open_mode from v$pdbs; NAME OPEN_MODE --------------- ---------- PDB$SEED READ ONLY ---// ---// set _oracle_script to false (not required if terminating session) //--- ---// SQL> alter session set "_oracle_script"=false; Session altered.
We have customized our seed pluggable database (pdb$seed) to meet additional standards and also reverted it to its original READ-ONLY state. We can now use the seed pluggable database to create additional pluggable databases according to our customized standards within the ROOT container as shown below.
---// ---// creating new PDB using the customized pdb$seed template PDB //--- ---// SQL> show con_name CON_NAME ------------------------------ CDB$ROOT SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO SQL> create pluggable database cdb1_pdb_1 admin user pdbadmin identified by oracle 2 file_name_convert=('/oradata/orpcdb1/pdbseed/','/oradata/orpcdb1/cdb1_pdb_1/') 3 ; Pluggable database created. ---// ---// validate new PDB is created //--- ---// SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 CDB1_PDB_1 MOUNTED ---// ---// open the new PDB //--- ---// SQL> alter pluggable database cdb1_pdb_1 open; Pluggable database altered.
We have created a new pluggable database using the customized pdb$seed template. Let’s validate if the customizations are visible within the newly created PDB.
---// ---// switch to the new PDB //--- ---// SQL> alter session set container=cdb1_pdb_1; Session altered. SQL> show con_name CON_NAME ------------------------------ CDB1_PDB_1 ---// ---// validate the customization within the new PDB //--- ---// SQL> select tablespace_name from dba_tablespaces order by tablespace_name; TABLESPACE_NAME --------------- AUDIT_DATA SYSAUX SYSTEM TEMP USER_DATA SQL> select username,default_tablespace,account_status 2 from dba_users where username='INFRA_USER'; USERNAME DEFAULT_TABLESPACE ACCOUNT_STATUS -------------------- ------------------------------ -------------------------------- INFRA_USER USER_DATA EXPIRED
As we can see, the customizations are visible within the newly created PDB. We could the additional tablespaces AUDIT_DATA and USER_DATA are created along with the local user INFRA_USER during the PDB creation from seed template.
The approach that I have demonstrated in this post leverage Oracle’s undocumented parameter. However, there are other ways to creat customized template. One such approach would be to create a new PDB using the default SEED template and then add all customization to the new PDB. Then we can put the new PDB in READ-ONLY mode and treat it as a standard template for creating any additional pluggable databases.