Skip to content
Keep Learning Keep Living
Keep Learning Keep Living
Keep Learning Keep Living

3 Ways to Migrate a Non-CDB Database to a PDB

Mustafa, 2022-03-252022-03-26

Hi Everyone,

Time is fast and everything is changing constantly. Multi-tenant architecture has come many years ago and starting by 21c, it is the only option! So,  old “non-cdb” databases must be migrated/converted to a PDB (Pluggable database). I must admin that I was being lazy for many years and I didn’t work much to learn new things and now I am literally trying to learn everything. One of the first goal was about multi-tenant architecture and now, since I feel that I am confident enough about it, I will move my clients’ databases to multi-tenant architecture. Also, I must say, I loved multi-tenant architecture.

I won’t be going details about what multi-tenant or a pdb is in this post. I will cover only Migration / Conversion.

So, for a long time I am testing about migrating noncdb databases to pdb and I want to explain 3 main methods to do that.

  • Plugging in a noncdb as pdb
  • Creating a pdb from noncdb over a database link (dblink)
  • Autoupgrade

Methods like export import can be used of course but I don’t think that can be count as a “migrate”. So, I won’t be talk about it in this post. Let’s start then.

Environment

For all 3 methods same environment is used: Oracle Linux 8.5 (virtual box), Oracle Database 19.14 Enterprise Edition. (I will add changes on 21c in my post)

Noncdb Database SID        : orcl
Multi-tenant Database SID: cdb

Both databases are in same home (could be in different homes, that would change nothing).

I always use OMF so I won’t be using FILE_PATH_CONVERT parameter in my examples. if you don’t use OMF (I don’t know why you do that) then you must use file_path_convert and point necessary directories.

I put around 4.5 GB of data in orcl (noncdb) database because amount of data will affect the completion time of the process.

By the way, I will suppress some outputs to keep it short and emphasis real results.

Pre Steps

Steps that I am about to show you should (must to me) do whatever method you are using to migrate your database. You must always check if noncdb database is applicable as a pdb. To do that, you will use simple pdb plug in method basically. Of course in this case, we cannot “unplug” our noncdb database because it is not a pdb, so what?

As you know, you can plug in and unplug a PDB to/from a container database in multi-tenant architecture. this is the coolest option I think. As if you are plugging in a pdb, you can plug in a noncdb as a PDB. While plugging in a pdb, we need an XML file that defines properties and necessary information about the pdb like compatibility, nls info, data file locations etc. To plug in a noncdb, we will need that file as well. Oracle already embedded a package to achieve that. DBMS_PDB. Describe procedure in this package will create XML file that we need.

if you are going to use PLUG IN method then put your source database (non-cdb database) into transactionally consistent state which means open it in READ ONLY mode. Reason is XML file contains some SCN information too but if db is up and running scn will move. When you tried to plug in database, you will get an error about data file scn number and config file (XML file) does not match. Other 2 methods doesn’t require that! I personally prefer this in db link method too. I don’t want any process keep doing something while converting a noncdb to pdb.

for plug in method:

Oracle PL/SQL
1
2
3
4
5
6
7
oracle@ol8_19c ~ $ export ORACLE_SID=orcl
oracle@ol8_19c ~ $ sqlplus / as sysdba
 
SQL> shutdown immediate;
...
SQL> startup open read only;
...

I connect to “orcl” database and create necessary xml file:

Oracle PL/SQL
1
2
3
4
5
6
oracle@ol8_19c ~ $ export ORACLE_SID=orcl
oracle@ol8_19c ~ $ sqlplus / as sysdba
 
SQL> exec dbms_pdb.describe('/tmp/orcl.xml');
 
PL/SQL procedure successfully completed.

Now we have an xml file that defines our noncdb database.

Then, check if this is a compatible database with our container database. Connect to CDB database and check the xml file:

Oracle PL/SQL
1
2
3
4
5
6
7
8
9
10
11
12
SQL> set serveroutput on
 
SQL> declare
  2    is_compatible  boolean ;
  3  begin
  4    is_compatible  := DBMS_PDB.CHECK_PLUG_COMPATIBILITY(pdb_descr_file => '/tmp/orcl.xml');
  5  DBMS_OUTPUT.PUT_LINE(Case is_compatible when True then 'YES' else 'NO' end);
  6  end;
  7  /
YES
 
PL/SQL procedure successfully completed.

DBMS_PDB has a function called “check_plug_compatibility”. this function reads XML file and returns true or false. if true then you can plug this noncdb as pdb (maybe not so fast). if result is false then you must check what is wrong? even if result of this function is true you must check “violations”. every CDB database has a data dictionary view called PDB_PLUG_IN_VIOLATIONS. After running “check_plug_compatibility” function, errors/warnings/infos will be written to this view and you must check them before plugging in the database.

Oracle PL/SQL
1
2
3
4
5
6
7
8
9
SQL> set linesize 200
SQL> column message format a80
SQL> column type format a10
SQL>
SQL> select message, type from pdb_plug_in_violations where name ='ORCL' and status <> 'RESOLVED';
 
MESSAGE TYPE
----------------------------------------------------------------- ----------
PDB plugged in is a non-CDB, requires noncdb_to_pdb.sql be run.  WARNING

if you see any ERROR in this view you must not proceed until solving the problem.  You might see various problems here like different database parameters like open_cursors could be 500 on noncdb but 300 on cdb. remember, cdb parameter values will override previous parameters.  (I will explain “PDB plugged in is a non-CDB, requires noncdb_to_pldb.sql be run” warning later)

Some important points are DB OPTIONS. Your databases might have different options. Let’s say your noncdb database has SPATIAL option installed but it is not installed on CDB. if so, then you must install SPATIAL option before plug in the database. how to install options on a database? You can check my previous post about it:  https://mustafakalayci.me/2022/03/03/how-to-install-oracle-database-options-like-spatial-label-security-etc-after-db-creation/

As a rule, your non-cdb database might have equal or less than compatible parameter value. if this is the situation you will see a row in PDB_PLUG_IN_VIOLATIONS.

if you resolve a problem on PDB_PLUG_IN_VIOLATIONS, it will still be there. even so, after solving a “warning” problem (like installing an option) will be listed as PENDING not resolved. it requires open the pluggable database.

As I said, these steps should be mandatory to you before migrating non-cdb to pdb. after checking violations, you can proceed to plug in operation.

1- Plugging in a Noncdb as PDB

At this point we should have checked the xml file and solved the violation problems. Please remember you should have created the XML file when noncdb database in READ ONLY mode!

Now, we have XML file so we can plug in noncdb as a pdb. Before do that, close source database (noncdb).

Oracle PL/SQL
1
2
3
4
oracle@ol8_19c ~ $ export ORACLE_SID=orcl
oracle@ol8_19c ~ $ sqlplus / as sysdba
 
SQL> shutdown immediate;

then connect to CDB and create a pluggable database via plug in:

Oracle PL/SQL
1
2
3
4
5
6
7
8
9
oracle@ol8_19c ~ $ export ORACLE_SID=cdb
oracle@ol8_19c ~ $ sqlplus / as sysdba
 
SQL> set timing on
SQL> Create pluggable database orcl using '/tmp/orcl.xml';
 
Pluggable database created.
 
Elapsed: 00:00:10.53

I don’t want to go to detail of create PDB via plug in but as a summary; you can use a different PDB name. instead of orcl, you can use orcl_pdb for example. Also, default mode for plugging in a pdb is COPY which means it will copy the datafiles that orcl.xml pointed out (they are under /u01/app/oracle/oradata/orcl directory currently). PLUG IN method will copy them under /u01/app/oracle/cdb directory (wherever db_create_file_dest is).  this way, noncdb database (orcl) will be still available (it is in shutdown state).

it takes 10 seconds to complete on my laptop. as I said before it has 4.5GB extra dummy data in this database. total size is around 7.5GB. 10 seconds is the time of copying datafiles to a new location. if you use MOVE instead of COPY method it will take much less time.

Oracle PL/SQL
1
2
3
4
5
6
7
8
9
10
11
oracle@ol8_19c ~ $ export ORACLE_SID=cdb
oracle@ol8_19c ~ $ sqlplus / as sysdba
 
SQL> drop pluggable database orcl including datafiles;
SQL> set timing on
 
SQL> create pluggable database orcl using '/tmp/orcl.xml' MOVE;
 
Pluggable database created.
 
Elapsed: 00:00:00.68

as you see it only takes 0.68 seconds. size of data is not matter now because data files are MOVEd to another location and this is a very fast operation. even if you have 1TB of data it will be completed in seconds. Also, if you are satisfied where datafiles reside currently, you can use NOCOPY option too.

if you use same with noncdb database then you must sure that noncdb is closed because there will be 2 services with same name.

you can use this method even if your databases are on different servers. just create XML file on noncdb database, then move datafiles and XML file to new server, modify XML file because file locations might be changed and wherever you copy the data files, change locations in XML file to new location and then run create pluggable database command.

Always check PDB_PLUG_IN_VIOLATIONS view after creating PDB because there might be new issues.

Now we have a new pdb called orcl:

Oracle PL/SQL
1
2
3
4
5
6
SQL> show pdbs;
 
    CON_ID CON_NAME   OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED   READ ONLY  NO
3 ORCL   MOUNTED

NOTE: Another amazing option we have is we can create a PDB from a lower version noncdb. for example, if you have a 12.2 noncdb database, just install 19c and follow the same steps. Cool right? there is only one thing to do! before calling noncdb_to_pdb.sql file run dbupgrade -c “ORCL” command on shell. dbupgrade is kind of a shortcut for catupgrd.sql file. this will upgrade your newly created pluggable database first.

as you see it is in MOUNTED mode which means it is closed but we CANNOT open it yet on 19c database. For 19c, we must connect to newly created pdb and run noncdb_to_pdb.sql script which is under $ORACLE_HOME/rdbms/admin

Oracle PL/SQL
1
2
3
4
5
6
7
8
SQL> alter session set container=orcl;
 
Session altered.
 
SQL> @?/rdbms/admin/noncdb_to_pdb.sql
...
...
...

it will take a while. as I said, don’t open pdb. set your container as new pdb then run noncdb_to_pdb.sql file. question mark means ORACLE_HOME in sqlplus. so I basically called @/u01/app/oracle/product/19c/dbhome_1/rdbms/admin/noncdb_to_pdb.sql

Oracle PL/SQL
1
2
3
4
5
6
7
8
9
SQL> show pdbs;
 
    CON_ID CON_NAME   OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED   READ ONLY  NO
3 ORCL   READ WRITE NO
SQL>  select message, type from pdb_plug_in_violations where status <> 'RESOLVED' and name ='ORCL';
 
no rows selected

21c UPDATE: After plugging in (create pluggable database) command, you don’t need to run dbupgrade (if noncdb is a lower db version) or noncdb_to_pdb.sql scripts. when you run ALTER PLUGGABLE DATABASE OPEN command, 21c will automatically run them but open command, of course, will take some time to complete.

That is it.

2- Create PDB from Non-CDB via DBLINK

This step is much easier for an Admin but takes much more time to complete. Good thing about this method is your source DB can stay open during the operation and when pdb creation is completed, it will apply archivelog of noncdb database. So, PDB will be transactionally consistent at the time of END of the pdb creation.

Do the PRE STEPs first as described above. create XML file and check for the violations. if everything is OK then, you can proceed.

This method just requires a database link (dblink) from CDB to NONCDB. Dblink must be created at the cdb$root container. First create a user on noncdb database which will be use to connect in dblink.

Oracle PL/SQL
1
2
3
4
5
6
7
8
9
10
oracle@ol8_19c ~ $ export ORACLE_SID=orcl
oracle@ol8_19c ~ $ sqlplus / as sysdba
 
SQL> create user dblink_user identified by oracle;
 
User created.
 
SQL> grant resource, connect, create pluggable database to dblink_user;
 
Grant succeeded.

Remember, this user must have resource, connect and create pluggable database privileges. after that create database link on CDB:

Oracle PL/SQL
1
2
3
4
5
6
7
oracle@ol8_19c ~ $ export ORACLE_SID=cdb
oracle@ol8_19c ~ $ sqlplus / as sysdba
 
SQL> create database link orcl_link connect to dblink_user identified by oracle
     using 'localhost/orcl';
 
Database link created.

from now on we will create a pdb from a remote link:

Oracle PL/SQL
1
2
3
4
5
6
7
8
oracle@ol8_19c ~ $ export ORACLE_SID=cdb
oracle@ol8_19c ~ $ sqlplus / as sysdba
 
SQL> set timing on
SQL> create pluggable database orcl from NON$CDB@orcl_link;
Pluggable database created.
 
Elapsed: 00:00:09.57

it completed in 10 seconds. if source database was bigger it would take much more time. Since non-cdb has no PDB name, we use NON$CDB.

as I explained in previous methods, for 19c, if you created pdb from a lower version run dbupgrade command. after that, you must set current container as new pdb and run noncdb_to_pdb.sql file.

Oracle PL/SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
SQL> show pdbs
 
    CON_ID CON_NAME   OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED   READ ONLY  NO
4 ORCL   MOUNTED
SQL> alter session set container=orcl;
 
Session altered.
 
SQL> @?/rdbms/admin/noncdb_to_pdb.sql
...
...
 
SQL> alter pluggable database orcl open;

if this is a 21c you can simply open pdb. 21c will do the job but open command will take some time.

I am not sure if this is supported (I did not checked yet but test it of course). I use this method to create a PDB from a noncdb which is on a different server and different OS and it worked!

3- Autoupgrade

New King of the upgrades/convertions/migrations 🙂 Autoupgrade is an amazing tool and support many options now. Even, I have just read that version 2 is released while I was writing this post on Mike Dietrich’s blog ( https://mikedietrichde.com/2022/03/25/autoupgrade-2-0-has-been-released-and-got-reuploaded/ )

You can use autoupgrade to convert a noncdb database to pdb. Autoupgrade will take care of everything even pre steps and post steps. It will even run the fix scripts.

I still would like to do my “Pre STEPS” to check the operation.

autoupgrade is a jar file and requires java to run but no worries, everything you need is in the ORACLE_HOME. Before take an action, always download the latest version of autoupgrade.jar file from https://support.oracle.com/epmos/faces/DocumentDisplay?id=2485457.1 it is a single jar file and put it under $ORACLE_HOME/rdbms/admin for 19c and above.

autoupgrade has different modes and I won’t detail all of them here. What we use here is ANALYZE and DEPLOY modes. ANALYZE mode will run all the steps just skipping the actual operations and will show you a result. After that you can run it in DEPLOY mode which will do the actual job. autoupgrade requires a config file to identify what to do and necessary info. here is my sample:

Oracle PL/SQL
1
2
3
4
5
6
7
8
9
10
11
12
global.autoupg_log_dir=/home/oracle/autoupgrade
 
upg1.log_dir=/home/oracle/autoupgrade
upg1.sid=orcl
upg1.source_home=/u01/app/oracle/product/19c/dbhome_1
upg1.target_cdb=cdb
upg1.target_home=/u01/app/oracle/product/19c/dbhome_1
upg1.target_pdb_name=my_pdb
upg1.start_time=now
upg1.upgrade_node=localhost
upg1.run_utlrp=yes
upg1.timezone_upg=yes

it is quite self explanatory. source is upg1.sid which is noncdb and upg1.target_cdb is cdb which autoupgrade understands this is a noncdb to pdb conversion. you can give a new name for your pdb (my_pdb in my example). define a start time, set if a timezone upgrade will be proceed etc. I saved this file under /home/oracle/noncdb_to_pdb.cfg.

EDIT: I forgot to mention about something. By default, autoupgrade will remove your noncdb! it is creating PDB with MOVE option so datafiles of noncdb are gone. if you want to prevent this, use KEEP_SOURCE_PDB=yes in your config file like:

upg1.keed_source_pdb=yes

Before Running Autoupgrade : This is an important note. it might be solved already because autoupgrade team is really fast but I had some problems while doing that because of glogin.sql file. for details: https://mustafakalayci.me/2022/03/20/666/ thanks to Mike Dietrich and Joseph Errede, they take care of it really fast.

just run autoupgrade in analyze mode first:

Oracle PL/SQL
1
2
3
4
oracle@ol8_19c ~ $ $ORACLE_HOME/jdk/bin/java -jar \
                 $ORACLE_HOME/rdbms/admin/autoupgrade.jar \
                 -mode ANALYZE \
                 -config /home/oracle/noncdb_to_pdb.cfg

then check the result and run it in DEPLOY mode. Deploy mode will start a CLI (command line interface) so you can watch the steps by typing “lsj” command:

Oracle PL/SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
oracle@ol8_19c ~ $ $ORACLE_HOME/jdk/bin/java -jar \
                 $ORACLE_HOME/rdbms/admin/autoupgrade.jar \
                 -mode DEPLOY \
                 -config /home/oracle/noncdb_to_pdb.cfg
 
AutoUpgrade 22.2.220324 launched with default internal options
Processing config file ...
+--------------------------------+
| Starting AutoUpgrade execution |
+--------------------------------+
1 Non-CDB(s) will be processed
Type 'help' to list console commands
 
upg> lsj
+----+-------+-----------+---------+-------+----------+-------+---------------------------+
|Job#|DB_NAME|      STAGE|OPERATION| STATUS|START_TIME|UPDATED|                    MESSAGE|
+----+-------+-----------+---------+-------+----------+-------+---------------------------+
| 101|   orcl|NONCDBTOPDB|EXECUTING|RUNNING|  05:45:08| 0s ago|Creating pluggable database|
+----+-------+-----------+---------+-------+----------+-------+---------------------------+
Total jobs 1
 
upg> lsj
+----+-------+-----------+---------+-------+----------+-------+-------------------+
|Job#|DB_NAME|      STAGE|OPERATION| STATUS|START_TIME|UPDATED|            MESSAGE|
+----+-------+-----------+---------+-------+----------+-------+-------------------+
| 101|   orcl|NONCDBTOPDB|EXECUTING|RUNNING|  05:45:08|48s ago|noncdb_to_pdb - 20%|
+----+-------+-----------+---------+-------+----------+-------+-------------------+
Total jobs 1

When operation is over it will automatically exit the cli and will print the log file locations. as you see in my example, it already started noncdb_to_pdb.sql file. Yes, all of those steps are automatic in autoupgrade.

here is the end:

Oracle PL/SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
upg> Job 101 completed
------------------- Final Summary --------------------
Number of databases            [ 1 ]
 
Jobs finished                  [1]
Jobs failed                    [0]
Jobs restored                  [0]
Jobs pending                   [0]
 
 
 
Please check the summary report at:
/home/oracle/autoupgrade/cfgtoollogs/upgrade/auto/status/status.html
/home/oracle/autoupgrade/cfgtoollogs/upgrade/auto/status/status.log

here is the html file screen shot:

that’s it.

19c 21c Administration Multi-tenant autoupgradeconvert noncdb to pdbmigrate noncdb to multi-tenantmigrate noncdb to pdbnon-cdb to pdbnoncdb to pdbnoncdb to pdb via dblinkplug in noncdb

Post navigation

Previous post
Next post

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Recent Posts

  • DDL Generation Failed with ORA-65047: Object SYS.KUPUTIL is invalid
  • How to call HTTPS Url Without SSL Wallet in 19c
  • Is Table Unnecessary for Pipelined Function
  • Password Rollover Time in Seconds
  • PDB Syncronization Issue
  • How to limit DB Link Connection Timeout
  • Cloud Base Database Service
  • 29th of February and interval

Recent Comments

  • Mustafa on How to call HTTPS Url Without SSL Wallet in 19c
  • Накрутка авито on How to call HTTPS Url Without SSL Wallet in 19c
  • Mustafa on Cloud Base Database Service
  • Raja on Cloud Base Database Service
  • Mustafa on Refreshable PDB and ORA-17627: ORA-12578: TNS:wallet open failed

Categories

  • 11g
  • 12c
  • 18c
  • 19c
  • 21c
  • 23ai
  • Administration
  • Cloud
  • Compression
  • Development
  • Materialized View
  • Multi-tenant
  • Performance
  • Security
  • SQL / PLSQL
  • Uncategorized
  • Undocumented
  • Useful Scripts

Archives

  • June 2025
  • April 2025
  • November 2024
  • July 2024
  • April 2024
  • February 2024
  • January 2024
  • December 2023
  • November 2023
  • October 2023
  • September 2023
  • August 2023
  • May 2023
  • April 2023
  • March 2023
  • February 2023
  • January 2023
  • November 2022
  • October 2022
  • September 2022
  • August 2022
  • July 2022
  • June 2022
  • May 2022
  • April 2022
  • March 2022
  • February 2022
  • January 2022
  • October 2021
  • September 2021
  • August 2021
  • April 2021
  • January 2021
  • December 2020
  • November 2020
  • October 2020
  • September 2020
  • August 2020
  • July 2020
  • June 2020
  • May 2020
  • April 2020
  • March 2020
  • February 2020
  • January 2020
  • December 2019
  • July 2019
  • June 2019
  • May 2019
  • March 2019
  • February 2019
  • June 2018

Meta

  • Log in
  • Entries feed
  • Comments feed
  • WordPress.org

RSS Follow This Blog

  • DDL Generation Failed with ORA-65047: Object SYS.KUPUTIL is invalid
  • How to call HTTPS Url Without SSL Wallet in 19c
  • Is Table Unnecessary for Pipelined Function
  • Password Rollover Time in Seconds
  • PDB Syncronization Issue
  • How to limit DB Link Connection Timeout
  • Cloud Base Database Service
  • 29th of February and interval
  • How to Copy Local Files to Oracle Object Storage
  • Guid vs Sequences

Archives

  • June 2025
  • April 2025
  • November 2024
  • July 2024
  • April 2024
  • February 2024
  • January 2024
  • December 2023
  • November 2023
  • October 2023
  • September 2023
  • August 2023
  • May 2023
  • April 2023
  • March 2023
  • February 2023
  • January 2023
  • November 2022
  • October 2022
  • September 2022
  • August 2022
  • July 2022
  • June 2022
  • May 2022
  • April 2022
  • March 2022
  • February 2022
  • January 2022
  • October 2021
  • September 2021
  • August 2021
  • April 2021
  • January 2021
  • December 2020
  • November 2020
  • October 2020
  • September 2020
  • August 2020
  • July 2020
  • June 2020
  • May 2020
  • April 2020
  • March 2020
  • February 2020
  • January 2020
  • December 2019
  • July 2019
  • June 2019
  • May 2019
  • March 2019
  • February 2019
  • June 2018

RSS Follow This Blog

  • DDL Generation Failed with ORA-65047: Object SYS.KUPUTIL is invalid
  • How to call HTTPS Url Without SSL Wallet in 19c
  • Is Table Unnecessary for Pipelined Function
  • Password Rollover Time in Seconds
  • PDB Syncronization Issue
  • How to limit DB Link Connection Timeout
  • Cloud Base Database Service
  • 29th of February and interval
  • How to Copy Local Files to Oracle Object Storage
  • Guid vs Sequences
RSS Error: A feed could not be found at `http://www.mywebsite.com/feed/`; the status code is `200` and content-type is `text/html; charset=UTF-8`
©2025 Keep Learning Keep Living | WordPress Theme by SuperbThemes