Migrate roles, users, and permissions from Oracle to PolarDB for PostgreSQL (Compatible with Oracle)
When you migrate your workloads from an Oracle database to PolarDB for PostgreSQL (Compatible with Oracle), you must fully replicate the original security model. This topic describes two migration methods. We recommend that you use the user and permission migration tool (polardb-schema-migration) to automate the migration. If your runtime environment cannot connect to both Oracle and PolarDB for PostgreSQL (Compatible with Oracle) at the same time, you can use SQL scripts to migrate manually.
Method selection
This topic provides the following two migration methods. Choose the one that fits your runtime environment.
|
Item |
Runtime requirements |
Efficiency |
Use case |
|
Method 1: (Recommended) Use the migration tool |
Requires a host that can connect to both Oracle and PolarDB for PostgreSQL (Compatible with Oracle) (for example, an ECS instance) with Java 1.8 installed. |
High. Run a single command to automatically complete all migration steps. |
Most scenarios. Recommended as the primary option. |
|
Method 2: Use SQL scripts |
No network connectivity required. Export SQL on the Oracle side by using SQL*Plus, then transfer the SQL files to a host that can access PolarDB for PostgreSQL (Compatible with Oracle) and import them by using psql. |
Medium. You must execute several SQL scripts manually, which makes the workflow tedious. |
You cannot provide a host that connects to both Oracle and PolarDB for PostgreSQL (Compatible with Oracle) because of network isolation or similar reasons. |
Method 1: (Recommended) Use the migration tool
Considerations
-
Oracle source requirements: The Oracle account used for the connection must have at least the
CONNECT,CREATE SESSION, andSELECT_CATALOG_ROLEprivileges. Use the following statement to grant them:GRANT CONNECT, CREATE SESSION, SELECT_CATALOG_ROLE TO myuser; -
PolarDB target requirements:
-
You must first use Data Transmission Service (DTS) to complete the schema migration from Oracle to PolarDB.
-
The account that connects to PolarDB must be a privileged account.
-
-
Tool runtime requirements:
-
The migration tool must be deployed on a host that can connect to both Oracle and PolarDB, such as an ECS instance.
-
The runtime environment must have Java 1.8 installed.
-
Deploy the tool
-
Download the migration tool JAR file polardb-schema-migration.jar and upload it to a host that can connect to both Oracle and PolarDB.
-
Run the following command to verify the tool version:
java -jar polardb-schema-migration.jar --version -
Create a
config.jsonfile with the following content. Adjust the database connection strings and log directory based on your environment. The migration process uses this configuration file.{ "source": { "url": "jdbc:oracle:thin:@//<OracleHostIP>:<port>/<serviceName>", "username": "<OracleUser>", "password": "<OraclePassword>" }, "destination": { "url": "jdbc:polardb://<PolarDBEndpoint>:<port>/<dbName>", "username": "<PolarDBUser>", "password": "<PolarDBPassword>" }, "log": { "dir": "/path/to/log" } }
Migration steps
Create roles
Run the following command to export role (ROLE) definitions from Oracle and create them in PolarDB.
# Adjust the paths of the JAR file and config file based on your environment. The same applies to the commands that follow.
java -jar polardb-schema-migration.jar --config=/path/to/config.json --create-roles
Create users
Run the following command to export user (USER) definitions from Oracle and create them in PolarDB.
java -jar polardb-schema-migration.jar --config=/path/to/config.json --create-users
Because passwords are encrypted in the source database, password migration is not supported. After migration to PolarDB, all users have no password. You must set a password manually for each user:
ALTER USER myuser PASSWORD '<new_password>';
Grant object privileges
Run the following command to export the object privilege (OBJECT PRIVILEGE) grant records from Oracle and apply them in PolarDB. This grants privileges such as table SELECT/INSERT/UPDATE/DELETE and function EXECUTE to roles and users.
java -jar polardb-schema-migration.jar --config=/path/to/config.json --grant-object-privileges
Grant roles
Run the following command to export the role grant records from Oracle and apply them in PolarDB. When a role is granted to a user, the user obtains the role's privileges.
java -jar polardb-schema-migration.jar --config=/path/to/config.json --grant-roles
Grant SCHEMA privileges
Run the following command to grant the USAGE privilege on schemas to regular users to align with Oracle behavior. Oracle does not check this privilege, which is equivalent to granting it by default.
java -jar polardb-schema-migration.jar --config=/path/to/config.json --grant-schema-usage
Modify object owners
In Oracle, SCHEMA and USER/OWNER are the same concept. In PolarDB, they are independent. Run the following command to change the OWNER of each object to the user with the same name as the schema, achieving consistent SCHEMA-OWNER mapping in PolarDB.
java -jar polardb-schema-migration.jar --config=/path/to/config.json --change-object-owner
(Optional) Grant system privileges
System privileges are an advanced Oracle feature that primarily control DDL execution. In PolarDB, we recommend that you use a privileged account for DDL operations. Therefore, you generally do not need to migrate system privileges.
Before you run this command, log on to the PolarDB console and enable the polar_enable_system_privilege parameter on the cluster Parameters page.
java -jar polardb-schema-migration.jar --config=/path/to/config.json --grant-system-privileges
(Optional) Set default roles
Default roles are an advanced Oracle feature that control which role privileges a user has by default after logon. In PolarDB, users automatically load privileges of all their granted roles at logon, which matches Oracle's default behavior. Therefore, you generally do not need to perform this migration step.
Before you run this command, log on to the PolarDB console and enable the polar_enable_default_role parameter on the cluster Parameters page.
java -jar polardb-schema-migration.jar --config=/path/to/config.json --set-default-roles
(Optional) Create PROFILEs
PROFILEs are an advanced Oracle feature for password complexity checks, expiration policies, and similar controls. In PolarDB, users and passwords are typically managed from the console. Therefore, you generally do not need to migrate PROFILEs.
java -jar polardb-schema-migration.jar --config=/path/to/config.json --create-profiles
Method 2: Use SQL scripts
In this method, you first run PL/SQL programs by using SQL*Plus on the Oracle side to export roles, users, and permissions into SQL scripts. Then, you use a client such as psql to execute the SQL scripts in PolarDB. This method does not require network connectivity between Oracle and PolarDB.
Considerations
-
Oracle source requirements: Prepare a migration account in Oracle. The account must have at least the connection and system catalog query privileges. Use the following statements to grant them:
CREATE USER <OracleUser> IDENTIFIED BY <OraclePassword>; GRANT CONNECT TO <OracleUser>; GRANT CREATE SESSION TO <OracleUser>; GRANT SELECT_CATALOG_ROLE TO <OracleUser>; -
PolarDB target requirements: Prepare a privileged account in PolarDB. You can create it in the PolarDB console.
-
Password migration limit: Because passwords are encrypted in Oracle, this method does not migrate passwords. All users have no password after migration to PolarDB; you must set the password manually.
-
Oracle version notes: This topic provides separate scripts for Oracle 12c and later, and for Oracle 11g.
-
For Oracle 12c and later, you can use the
ORACLE_MAINTAINED='N'column in system views to efficiently filter out Oracle system users and roles. -
For Oracle 11g, the column is not available, so you must filter system objects by listing their common names explicitly. If some objects are not filtered in your environment, adjust the filter list dynamically.
-
Migration steps
Create roles
Run the following PL/SQL script in SQL*Plus to export the CREATE ROLE statements for all roles to the create_role.sql file (you can specify the output path in the SPOOL directive). Then, transfer the file to the PolarDB side and run it by using psql.
Oracle 12c and later
SET HEADING OFF
SET TRIMSPOOL ON
SET TRIMOUT ON
SET PAGESIZE 0
SET LINESIZE 2000
SET SERVEROUTPUT ON
-- The actual storage location for the output file. Adjust as needed.
SPOOL /my/path/to/create_role.sql
BEGIN
FOR rec IN (
SELECT 'CREATE ROLE ' || ROLE || ';' AS ddl_script
FROM DBA_ROLES
WHERE ORACLE_MAINTAINED = 'N'
ORDER BY ROLE
) LOOP
DBMS_OUTPUT.PUT_LINE(rec.ddl_script);
END LOOP;
END;
/
SPOOL OFF
EXIT
Oracle 11g
SET HEADING OFF
SET TRIMSPOOL ON
SET TRIMOUT ON
SET PAGESIZE 0
SET LINESIZE 2000
SET SERVEROUTPUT ON
SPOOL /my/path/to/create_role.sql
BEGIN
FOR rec IN (
SELECT 'CREATE ROLE ' || ROLE || ';' AS ddl_script
FROM DBA_ROLES
WHERE ROLE NOT IN (
'CONNECT', 'RESOURCE', 'DBA', 'SELECT_CATALOG_ROLE',
'EXECUTE_CATALOG_ROLE', 'DELETE_CATALOG_ROLE', 'EXP_FULL_DATABASE',
'IMP_FULL_DATABASE', 'LOGSTDBY_ADMINISTRATOR', 'RECOVERY_CATALOG_OWNER',
'SCHEDULER_ADMIN', 'HS_ADMIN_SELECT_ROLE', 'HS_ADMIN_EXECUTE_ROLE',
'HS_ADMIN_ROLE', 'GLOBAL_AQ_USER_ROLE', 'OEM_ADVISOR', 'OEM_MONITOR',
'MGMT_USER', 'DATAPUMP_EXP_FULL_DATABASE', 'DATAPUMP_IMP_FULL_DATABASE',
'ADM_PARALLEL_EXECUTE_TASK', 'GATHER_SYSTEM_STATISTICS',
'OPTIMIZER_PROCESSING_RATE', 'ACCESS_CATALOG_ROLE', 'JAVAUSERPRIV',
'JAVAIDPRIV', 'JAVASYSPRIV', 'JAVADEBUGPRIV', 'EJBCLIENT', 'JMXSERVER',
'JAVA_ADMIN', 'JAVA_DEPLOY', 'AUTHENTICATEDUSER', 'XDB_SET_INVOKER',
'XDB_WEBSERVICES', 'XDB_WEBSERVICES_WITH_PUBLIC', 'XDB_WEBSERVICES_OVER_HTTP',
'XDBADMIN', 'XDB_WEBSERVICES_OVER_HTTPS', 'CTXAPP', 'ORDADMIN',
'WM_ADMIN_ROLE', 'OLAP_USER', 'OLAP_DBA', 'OLAP_XS_ADMIN',
'CSW_USR_ROLE', 'WFS_USR_ROLE', 'SPATIAL_CSW_ADMIN',
'SPATIAL_WFS_ADMIN', 'LBAC_DBA', 'APEX_ADMINISTRATOR_ROLE',
'FLOWS_FILES_ROLE', 'AQ_ADMINISTRATOR_ROLE', 'AQ_USER_ROLE',
'CWM_USER', 'DBFS_ROLE', 'OLAPI_TRACE_USER', 'OWB$CLIENT',
'OWB_DESIGNCENTER_VIEW', 'OWB_USER'
)
AND ROLE NOT LIKE 'APEX\_%' ESCAPE '\'
AND ROLE NOT LIKE 'FLOWS\_%' ESCAPE '\'
AND ROLE NOT LIKE 'ORA\_%' ESCAPE '\'
AND ROLE NOT LIKE 'ORACLE\_%' ESCAPE '\'
AND ROLE NOT LIKE 'SYS\_%' ESCAPE '\'
ORDER BY ROLE
) LOOP
DBMS_OUTPUT.PUT_LINE(rec.ddl_script);
END LOOP;
END;
/
SPOOL OFF
EXIT
Create users
Run the following PL/SQL script in SQL*Plus to export the CREATE USER statements for all users. Then, transfer the SQL file to the PolarDB side and run it by using psql.
Oracle 12c and later
SET HEADING OFF
SET TRIMSPOOL ON
SET TRIMOUT ON
SET PAGESIZE 0
SET LINESIZE 2000
SET SERVEROUTPUT ON
SPOOL /my/path/to/create_user.sql
BEGIN
FOR rec IN (
SELECT 'CREATE USER ' || USERNAME || ';' AS ddl_script
FROM DBA_USERS
WHERE ORACLE_MAINTAINED = 'N'
ORDER BY USERNAME
) LOOP
DBMS_OUTPUT.PUT_LINE(rec.ddl_script);
END LOOP;
END;
/
SPOOL OFF
EXIT
Oracle 11g
SET HEADING OFF
SET TRIMSPOOL ON
SET TRIMOUT ON
SET PAGESIZE 0
SET LINESIZE 2000
SET SERVEROUTPUT ON
SPOOL /my/path/to/create_user.sql
BEGIN
FOR rec IN (
SELECT 'CREATE USER ' || USERNAME || ';' AS ddl_script
FROM DBA_USERS
WHERE USERNAME NOT IN (
'SYS', 'SYSTEM', 'DBSNMP', 'SYSMAN', 'OUTLN',
'CTXSYS', 'MDSYS', 'ORDSYS', 'ORDDATA', 'ORDPLUGINS', 'SI_INFORMTN_SCHEMA',
'WMSYS', 'EXFSYS', 'LBACSYS', 'XDB', 'ANONYMOUS', 'XS$NULL',
'OLAPSYS', 'MDDATA', 'OWBSYS', 'OWBSYS_AUDIT',
'APEX_030200', 'APEX_040000', 'APEX_040100', 'APEX_040200', 'APEX_050000',
'APEX_PUBLIC_USER', 'FLOWS_FILES', 'FLOWS_030000', 'FLOWS_040000',
'SPATIAL_CSW_ADMIN_USR', 'SPATIAL_WFS_ADMIN_USR',
'DIP', 'ORACLE_OCM', 'APPQOSSYS', 'MGMT_VIEW', 'SCOTT', 'HR',
'TSMSYS', 'WKPROXY', 'WK_TEST', 'PERFSTAT', 'TRACESVR',
'GSMADMIN_INTERNAL', 'GSMCATUSER', 'GSMUSER', 'SYSBACKUP', 'SYSDG', 'SYSKM'
)
AND USERNAME NOT LIKE 'APEX\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'FLOWS\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'ORA\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'ORACLE\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'SYS\_%' ESCAPE '\'
ORDER BY USERNAME
) LOOP
DBMS_OUTPUT.PUT_LINE(rec.ddl_script);
END LOOP;
END;
/
SPOOL OFF
EXIT
Because passwords are encrypted in Oracle, the exported CREATE USER statements do not include passwords. All users have no password after migration to PolarDB; you must set the password manually for each user:
ALTER USER <username> WITH PASSWORD '<new_password>';
Grant object privileges
Run the following PL/SQL script in SQL*Plus to export object privilege (OBJECT PRIVILEGE) GRANT statements to the grant_object.sql file. Then, transfer the file to the PolarDB side and run it by using psql. The script grants privileges such as table SELECT/INSERT/UPDATE/DELETE and function EXECUTE to roles and users.
The export script uses LISTAGG to merge multiple privileges on the same object for the same GRANTEE into a single GRANT statement (for example, SELECT, INSERT, and UPDATE are merged into GRANT SELECT, INSERT, UPDATE ON ...) and groups them by GRANTABLE (YES/NO) because WITH GRANT OPTION applies to the entire statement.
When an object has many privileges, the LISTAGG result may exceed 4000 bytes and cause the ORA-01489 error. In this case, remove LISTAGG and emit one GRANT statement per privilege.
Oracle 12c and later
SET HEADING OFF
SET TRIMSPOOL ON
SET TRIMOUT ON
SET PAGESIZE 0
SET LINESIZE 2000
SET DEFINE OFF
SET SERVEROUTPUT ON
SPOOL /my/path/to/grant_object.sql
BEGIN
FOR rec IN (
SELECT
'GRANT ' || LISTAGG(p.PRIVILEGE, ', ') WITHIN GROUP (ORDER BY p.PRIVILEGE) || ' ON ' ||
CASE WHEN MIN(o.OBJECT_TYPE) IN ('PROCEDURE', 'FUNCTION', 'TYPE') THEN MIN(o.OBJECT_TYPE) || ' '
ELSE '' END ||
'"' || p.OWNER || '"."' || p.TABLE_NAME || '" TO ' || p.GRANTEE ||
CASE WHEN p.GRANTABLE = 'YES' THEN ' WITH GRANT OPTION' ELSE '' END ||
';' AS ddl_script
FROM DBA_TAB_PRIVS p
JOIN DBA_OBJECTS o ON p.TABLE_NAME = o.OBJECT_NAME AND o.OWNER = p.OWNER
WHERE p.OWNER IN (SELECT USERNAME FROM DBA_USERS WHERE ORACLE_MAINTAINED = 'N')
AND p.TABLE_NAME NOT LIKE 'ISEQ$$%'
AND p.TABLE_NAME NOT LIKE 'AQ$%'
AND o.OBJECT_TYPE NOT IN ('QUEUE', 'PACKAGE BODY', 'TYPE BODY')
AND p.GRANTEE IN (
SELECT USERNAME FROM DBA_USERS WHERE ORACLE_MAINTAINED = 'N'
UNION
SELECT ROLE FROM DBA_ROLES
UNION
SELECT 'PUBLIC' FROM DUAL
)
GROUP BY p.GRANTEE, p.OWNER, p.TABLE_NAME, p.GRANTABLE
ORDER BY p.GRANTEE, p.OWNER, p.TABLE_NAME, p.GRANTABLE
) LOOP
DBMS_OUTPUT.PUT_LINE(rec.ddl_script);
END LOOP;
END;
/
SPOOL OFF
EXIT
Oracle 11g
SET HEADING OFF
SET TRIMSPOOL ON
SET TRIMOUT ON
SET PAGESIZE 0
SET LINESIZE 2000
SET DEFINE OFF
SET SERVEROUTPUT ON
SPOOL /my/path/to/grant_object.sql
BEGIN
FOR rec IN (
SELECT
'GRANT ' || LISTAGG(p.PRIVILEGE, ', ') WITHIN GROUP (ORDER BY p.PRIVILEGE) || ' ON ' ||
CASE WHEN MIN(o.OBJECT_TYPE) IN ('PROCEDURE', 'FUNCTION', 'TYPE') THEN MIN(o.OBJECT_TYPE) || ' '
ELSE '' END ||
'"' || p.OWNER || '"."' || p.TABLE_NAME || '" TO ' || p.GRANTEE ||
CASE WHEN p.GRANTABLE = 'YES' THEN ' WITH GRANT OPTION' ELSE '' END ||
';' AS ddl_script
FROM DBA_TAB_PRIVS p
JOIN DBA_OBJECTS o ON p.TABLE_NAME = o.OBJECT_NAME AND o.OWNER = p.OWNER
WHERE p.OWNER IN (
SELECT USERNAME FROM DBA_USERS WHERE USERNAME NOT IN (
'SYS', 'SYSTEM', 'DBSNMP', 'SYSMAN', 'OUTLN',
'CTXSYS', 'MDSYS', 'ORDSYS', 'ORDDATA', 'ORDPLUGINS', 'SI_INFORMTN_SCHEMA',
'WMSYS', 'EXFSYS', 'LBACSYS', 'XDB', 'ANONYMOUS', 'XS$NULL',
'OLAPSYS', 'MDDATA', 'OWBSYS', 'OWBSYS_AUDIT',
'APEX_030200', 'APEX_040000', 'APEX_040100', 'APEX_040200', 'APEX_050000',
'APEX_PUBLIC_USER', 'FLOWS_FILES', 'FLOWS_030000', 'FLOWS_040000',
'SPATIAL_CSW_ADMIN_USR', 'SPATIAL_WFS_ADMIN_USR',
'DIP', 'ORACLE_OCM', 'APPQOSSYS', 'MGMT_VIEW', 'SCOTT', 'HR',
'TSMSYS', 'WKPROXY', 'WK_TEST', 'PERFSTAT', 'TRACESVR',
'GSMADMIN_INTERNAL', 'GSMCATUSER', 'GSMUSER', 'SYSBACKUP', 'SYSDG', 'SYSKM'
)
AND USERNAME NOT LIKE 'APEX\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'FLOWS\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'ORA\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'ORACLE\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'SYS\_%' ESCAPE '\'
)
AND p.TABLE_NAME NOT LIKE 'ISEQ$$%'
AND p.TABLE_NAME NOT LIKE 'AQ$%'
AND o.OBJECT_TYPE NOT IN ('QUEUE', 'PACKAGE BODY', 'TYPE BODY')
AND p.GRANTEE IN (
SELECT USERNAME FROM DBA_USERS WHERE USERNAME NOT IN (
'SYS', 'SYSTEM', 'DBSNMP', 'SYSMAN', 'OUTLN',
'CTXSYS', 'MDSYS', 'ORDSYS', 'ORDDATA', 'ORDPLUGINS', 'SI_INFORMTN_SCHEMA',
'WMSYS', 'EXFSYS', 'LBACSYS', 'XDB', 'ANONYMOUS', 'XS$NULL',
'OLAPSYS', 'MDDATA', 'OWBSYS', 'OWBSYS_AUDIT',
'APEX_030200', 'APEX_040000', 'APEX_040100', 'APEX_040200', 'APEX_050000',
'APEX_PUBLIC_USER', 'FLOWS_FILES', 'FLOWS_030000', 'FLOWS_040000',
'SPATIAL_CSW_ADMIN_USR', 'SPATIAL_WFS_ADMIN_USR',
'DIP', 'ORACLE_OCM', 'APPQOSSYS', 'MGMT_VIEW', 'SCOTT', 'HR',
'TSMSYS', 'WKPROXY', 'WK_TEST', 'PERFSTAT', 'TRACESVR',
'GSMADMIN_INTERNAL', 'GSMCATUSER', 'GSMUSER', 'SYSBACKUP', 'SYSDG', 'SYSKM'
)
AND USERNAME NOT LIKE 'APEX\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'FLOWS\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'ORA\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'ORACLE\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'SYS\_%' ESCAPE '\'
UNION
SELECT ROLE FROM DBA_ROLES
UNION
SELECT 'PUBLIC' FROM DUAL
)
GROUP BY p.GRANTEE, p.OWNER, p.TABLE_NAME, p.GRANTABLE
ORDER BY p.GRANTEE, p.OWNER, p.TABLE_NAME, p.GRANTABLE
) LOOP
DBMS_OUTPUT.PUT_LINE(rec.ddl_script);
END LOOP;
END;
/
SPOOL OFF
EXIT
Grant roles
Run the following PL/SQL script in SQL*Plus to export the role grant GRANT statements. Then, transfer the SQL file to the PolarDB side and run it by using psql. When a role is granted to a user, the user obtains the role's privileges.
Oracle 12c and later
SET HEADING OFF
SET TRIMSPOOL ON
SET TRIMOUT ON
SET PAGESIZE 0
SET LINESIZE 2000
SET SERVEROUTPUT ON
SPOOL /my/path/to/grant_role.sql
BEGIN
FOR rec IN (
WITH NON_ORACLE_USERS_AND_ROLES AS (
SELECT USERNAME AS NAME FROM DBA_USERS WHERE ORACLE_MAINTAINED = 'N'
UNION
SELECT ROLE AS NAME FROM DBA_ROLES WHERE ORACLE_MAINTAINED = 'N'
),
FILTERED_ROLE_PRIVS AS (
SELECT GRANTEE, GRANTED_ROLE, ADMIN_OPTION
FROM DBA_ROLE_PRIVS
WHERE GRANTEE IN (SELECT NAME FROM NON_ORACLE_USERS_AND_ROLES)
)
SELECT
CASE
WHEN ADMIN_OPTION = 'YES' THEN
'GRANT ' || GRANTED_ROLE || ' TO ' || GRANTEE || ' WITH ADMIN OPTION;'
ELSE
'GRANT ' || GRANTED_ROLE || ' TO ' || GRANTEE || ';'
END AS ddl_script
FROM FILTERED_ROLE_PRIVS
ORDER BY GRANTEE, GRANTED_ROLE
) LOOP
DBMS_OUTPUT.PUT_LINE(rec.ddl_script);
END LOOP;
END;
/
SPOOL OFF
EXIT
Oracle 11g
SET HEADING OFF
SET TRIMSPOOL ON
SET TRIMOUT ON
SET PAGESIZE 0
SET LINESIZE 2000
SET SERVEROUTPUT ON
SPOOL /my/path/to/grant_role.sql
BEGIN
FOR rec IN (
WITH NON_ORACLE_USERS_AND_ROLES AS (
SELECT USERNAME AS NAME FROM DBA_USERS WHERE USERNAME NOT IN (
'SYS', 'SYSTEM', 'DBSNMP', 'SYSMAN', 'OUTLN',
'CTXSYS', 'MDSYS', 'ORDSYS', 'ORDDATA', 'ORDPLUGINS', 'SI_INFORMTN_SCHEMA',
'WMSYS', 'EXFSYS', 'LBACSYS', 'XDB', 'ANONYMOUS', 'XS$NULL',
'OLAPSYS', 'MDDATA', 'OWBSYS', 'OWBSYS_AUDIT',
'APEX_030200', 'APEX_040000', 'APEX_040100', 'APEX_040200', 'APEX_050000',
'APEX_PUBLIC_USER', 'FLOWS_FILES', 'FLOWS_030000', 'FLOWS_040000',
'SPATIAL_CSW_ADMIN_USR', 'SPATIAL_WFS_ADMIN_USR',
'DIP', 'ORACLE_OCM', 'APPQOSSYS', 'MGMT_VIEW', 'SCOTT', 'HR',
'TSMSYS', 'WKPROXY', 'WK_TEST', 'PERFSTAT', 'TRACESVR',
'GSMADMIN_INTERNAL', 'GSMCATUSER', 'GSMUSER', 'SYSBACKUP', 'SYSDG', 'SYSKM'
)
AND USERNAME NOT LIKE 'APEX\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'FLOWS\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'ORA\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'ORACLE\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'SYS\_%' ESCAPE '\'
UNION
SELECT ROLE AS NAME FROM DBA_ROLES WHERE ROLE NOT IN (
'CONNECT', 'RESOURCE', 'DBA', 'SELECT_CATALOG_ROLE',
'EXECUTE_CATALOG_ROLE', 'DELETE_CATALOG_ROLE', 'EXP_FULL_DATABASE',
'IMP_FULL_DATABASE', 'LOGSTDBY_ADMINISTRATOR', 'RECOVERY_CATALOG_OWNER',
'SCHEDULER_ADMIN', 'HS_ADMIN_SELECT_ROLE', 'HS_ADMIN_EXECUTE_ROLE',
'HS_ADMIN_ROLE', 'GLOBAL_AQ_USER_ROLE', 'OEM_ADVISOR', 'OEM_MONITOR',
'MGMT_USER', 'DATAPUMP_EXP_FULL_DATABASE', 'DATAPUMP_IMP_FULL_DATABASE',
'ADM_PARALLEL_EXECUTE_TASK', 'GATHER_SYSTEM_STATISTICS',
'OPTIMIZER_PROCESSING_RATE', 'ACCESS_CATALOG_ROLE', 'JAVAUSERPRIV',
'JAVAIDPRIV', 'JAVASYSPRIV', 'JAVADEBUGPRIV', 'EJBCLIENT', 'JMXSERVER',
'JAVA_ADMIN', 'JAVA_DEPLOY', 'AUTHENTICATEDUSER', 'XDB_SET_INVOKER',
'XDB_WEBSERVICES', 'XDB_WEBSERVICES_WITH_PUBLIC', 'XDB_WEBSERVICES_OVER_HTTP',
'XDBADMIN', 'XDB_WEBSERVICES_OVER_HTTPS', 'CTXAPP', 'ORDADMIN',
'WM_ADMIN_ROLE', 'OLAP_USER', 'OLAP_DBA', 'OLAP_XS_ADMIN',
'CSW_USR_ROLE', 'WFS_USR_ROLE', 'SPATIAL_CSW_ADMIN',
'SPATIAL_WFS_ADMIN', 'LBAC_DBA', 'APEX_ADMINISTRATOR_ROLE',
'FLOWS_FILES_ROLE', 'AQ_ADMINISTRATOR_ROLE', 'AQ_USER_ROLE',
'CWM_USER', 'DBFS_ROLE', 'OLAPI_TRACE_USER', 'OWB$CLIENT',
'OWB_DESIGNCENTER_VIEW', 'OWB_USER'
)
AND ROLE NOT LIKE 'APEX\_%' ESCAPE '\'
AND ROLE NOT LIKE 'FLOWS\_%' ESCAPE '\'
AND ROLE NOT LIKE 'ORA\_%' ESCAPE '\'
AND ROLE NOT LIKE 'ORACLE\_%' ESCAPE '\'
AND ROLE NOT LIKE 'SYS\_%' ESCAPE '\'
),
FILTERED_ROLE_PRIVS AS (
SELECT GRANTEE, GRANTED_ROLE, ADMIN_OPTION
FROM DBA_ROLE_PRIVS
WHERE GRANTEE IN (SELECT NAME FROM NON_ORACLE_USERS_AND_ROLES)
)
SELECT
CASE
WHEN ADMIN_OPTION = 'YES' THEN
'GRANT ' || GRANTED_ROLE || ' TO ' || GRANTEE || ' WITH ADMIN OPTION;'
ELSE
'GRANT ' || GRANTED_ROLE || ' TO ' || GRANTEE || ';'
END AS ddl_script
FROM FILTERED_ROLE_PRIVS
ORDER BY GRANTEE, GRANTED_ROLE
) LOOP
DBMS_OUTPUT.PUT_LINE(rec.ddl_script);
END LOOP;
END;
/
SPOOL OFF
EXIT
Grant SCHEMA privileges
In Oracle, accessing an object only requires verifying that the current user has the object privilege. In PolarDB, the database first verifies that the user has the privilege on the schema (SCHEMA) that the object belongs to, then verifies the object privilege. To align with Oracle, run the following PL/pgSQL script in PolarDB to grant USAGE on all user schemas to all users:
DO $$
DECLARE
schema_rec RECORD;
sql_stmt TEXT;
BEGIN
FOR schema_rec IN
SELECT nspname FROM pg_namespace n
WHERE nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast',
'polar_catalog', 'sys', 'cron', 'wmsys', 'polar_feature_utils',
'pg_bitmapindex', 'polar_dbms_stats', 'public')
AND nspname NOT LIKE 'pg_temp_%' AND nspname NOT LIKE 'pg_toast_temp_%'
AND nsppkgns = 0
ORDER BY nspname
LOOP
sql_stmt := format('GRANT USAGE ON SCHEMA %I TO PUBLIC', schema_rec.nspname);
RAISE NOTICE '%', sql_stmt;
EXECUTE sql_stmt;
END LOOP;
END $$;
Modify object owners
In Oracle, USER and SCHEMA are equivalent. Each user owns all objects in the schema with the same name by default. In PolarDB, users and schemas are independent. A user does not necessarily have privileges on the schema with the same name. To align with Oracle, run the following PL/pgSQL script (with a privileged account) in PolarDB by using psql to change the OWNER of each schema and all its objects to the user with the same name:
DO $$
DECLARE
obj_rec RECORD;
sql_stmt TEXT;
processed INTEGER := 0;
BEGIN
-- 1. Modify SCHEMA owners
FOR obj_rec IN
SELECT nspname FROM pg_namespace n
WHERE nspname IN (SELECT rolname FROM pg_roles WHERE rolsuper = false)
AND EXISTS (SELECT 1 FROM information_schema.schemata s WHERE s.schema_name = n.nspname)
AND nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast',
'polar_catalog', 'sys', 'cron', 'wmsys', 'polar_feature_utils',
'pg_bitmapindex', 'polar_dbms_stats', 'public')
AND nspname NOT LIKE 'pg_temp_%' AND nspname NOT LIKE 'pg_toast_temp_%'
AND nsppkgns = 0
AND (SELECT rolname FROM pg_roles WHERE oid = n.nspowner) != n.nspname
ORDER BY nspname
LOOP
sql_stmt := format('ALTER SCHEMA %I OWNER TO %I', obj_rec.nspname, obj_rec.nspname);
RAISE NOTICE '%', sql_stmt;
EXECUTE sql_stmt;
processed := processed + 1;
END LOOP;
-- 2. Modify TABLE owners
FOR obj_rec IN
SELECT schemaname, tablename FROM pg_tables t
WHERE schemaname IN (SELECT rolname FROM pg_roles WHERE rolsuper = false)
AND EXISTS (SELECT 1 FROM information_schema.schemata s WHERE s.schema_name = t.schemaname)
AND schemaname NOT IN ('information_schema', 'pg_catalog', 'pg_toast',
'polar_catalog', 'sys', 'cron', 'wmsys', 'polar_feature_utils',
'pg_bitmapindex', 'polar_dbms_stats', 'public')
AND t.tableowner != t.schemaname
ORDER BY schemaname, tablename
LOOP
sql_stmt := format('ALTER TABLE %I.%I OWNER TO %I', obj_rec.schemaname, obj_rec.tablename, obj_rec.schemaname);
RAISE NOTICE '%', sql_stmt;
EXECUTE sql_stmt;
processed := processed + 1;
END LOOP;
-- 2.1 Modify TABLE PARTITION owners
-- ALTER TABLE on the parent table does not cascade to partitions; modify each partition individually.
FOR obj_rec IN
SELECT n.nspname AS schemaname, c.relname AS tablename
FROM pg_class c
JOIN pg_namespace n ON c.relnamespace = n.oid
JOIN pg_inherits i ON c.oid = i.inhrelid
WHERE n.nspname IN (SELECT rolname FROM pg_roles WHERE rolsuper = false)
AND EXISTS (SELECT 1 FROM information_schema.schemata s WHERE s.schema_name = n.nspname)
AND n.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast',
'polar_catalog', 'sys', 'cron', 'wmsys', 'polar_feature_utils',
'pg_bitmapindex', 'polar_dbms_stats', 'public')
AND c.relkind = 'r'
AND c.relispartition = true
AND (SELECT rolname FROM pg_roles WHERE oid = c.relowner) != n.nspname
ORDER BY n.nspname, c.relname
LOOP
sql_stmt := format('ALTER TABLE %I.%I OWNER TO %I', obj_rec.schemaname, obj_rec.tablename, obj_rec.schemaname);
RAISE NOTICE '%', sql_stmt;
EXECUTE sql_stmt;
processed := processed + 1;
END LOOP;
-- 3. Modify VIEW owners
FOR obj_rec IN
SELECT schemaname, viewname FROM pg_views v
WHERE schemaname IN (SELECT rolname FROM pg_roles WHERE rolsuper = false)
AND EXISTS (SELECT 1 FROM information_schema.schemata s WHERE s.schema_name = v.schemaname)
AND schemaname NOT IN ('information_schema', 'pg_catalog', 'pg_toast',
'polar_catalog', 'sys', 'cron', 'wmsys', 'polar_feature_utils',
'pg_bitmapindex', 'polar_dbms_stats', 'public')
AND v.viewowner != v.schemaname
ORDER BY schemaname, viewname
LOOP
sql_stmt := format('ALTER VIEW %I.%I OWNER TO %I', obj_rec.schemaname, obj_rec.viewname, obj_rec.schemaname);
RAISE NOTICE '%', sql_stmt;
EXECUTE sql_stmt;
processed := processed + 1;
END LOOP;
-- 4. Modify MATERIALIZED VIEW owners
FOR obj_rec IN
SELECT schemaname, matviewname FROM pg_matviews mv
WHERE schemaname IN (SELECT rolname FROM pg_roles WHERE rolsuper = false)
AND EXISTS (SELECT 1 FROM information_schema.schemata s WHERE s.schema_name = mv.schemaname)
AND schemaname NOT IN ('information_schema', 'pg_catalog', 'pg_toast',
'polar_catalog', 'sys', 'cron', 'wmsys', 'polar_feature_utils',
'pg_bitmapindex', 'polar_dbms_stats', 'public')
AND mv.matviewowner != mv.schemaname
ORDER BY schemaname, matviewname
LOOP
sql_stmt := format('ALTER MATERIALIZED VIEW %I.%I OWNER TO %I', obj_rec.schemaname, obj_rec.matviewname, obj_rec.schemaname);
RAISE NOTICE '%', sql_stmt;
EXECUTE sql_stmt;
processed := processed + 1;
END LOOP;
-- 5. Modify SEQUENCE owners
FOR obj_rec IN
SELECT schemaname, sequencename FROM pg_sequences s
WHERE schemaname IN (SELECT rolname FROM pg_roles WHERE rolsuper = false)
AND EXISTS (SELECT 1 FROM information_schema.schemata s2 WHERE s2.schema_name = s.schemaname)
AND schemaname NOT IN ('information_schema', 'pg_catalog', 'pg_toast',
'polar_catalog', 'sys', 'cron', 'wmsys', 'polar_feature_utils',
'pg_bitmapindex', 'polar_dbms_stats', 'public')
AND s.sequenceowner != s.schemaname
ORDER BY schemaname, sequencename
LOOP
sql_stmt := format('ALTER SEQUENCE %I.%I OWNER TO %I', obj_rec.schemaname, obj_rec.sequencename, obj_rec.schemaname);
RAISE NOTICE '%', sql_stmt;
EXECUTE sql_stmt;
processed := processed + 1;
END LOOP;
-- 6. Modify FUNCTION owners (excluding functions inside extensions and packages)
FOR obj_rec IN
SELECT n.nspname AS schemaname, p.proname AS funcname,
pg_get_function_identity_arguments(p.oid) AS args,
CASE WHEN n.nspname = 'public' THEN 'PUBLIC' ELSE n.nspname END AS new_owner
FROM pg_proc p JOIN pg_namespace n ON p.pronamespace = n.oid
WHERE EXISTS (SELECT 1 FROM information_schema.schemata s WHERE s.schema_name = n.nspname)
AND n.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast',
'polar_catalog', 'sys', 'cron', 'wmsys', 'polar_feature_utils',
'pg_bitmapindex', 'polar_dbms_stats')
AND n.nspname NOT LIKE 'pg_temp_%' AND n.nspname NOT LIKE 'pg_toast_temp_%'
AND nsppkgns = 0 AND p.prokind = 'f'
AND NOT EXISTS (SELECT 1 FROM pg_depend d WHERE d.objid = p.oid AND d.deptype = 'e')
AND (SELECT rolname FROM pg_roles WHERE oid = p.proowner) !=
CASE WHEN n.nspname = 'public' THEN 'PUBLIC' ELSE n.nspname END
ORDER BY n.nspname, p.proname
LOOP
sql_stmt := format('ALTER FUNCTION %I.%I(%s) OWNER TO %I',
obj_rec.schemaname, obj_rec.funcname, obj_rec.args, obj_rec.new_owner);
RAISE NOTICE '%', sql_stmt;
EXECUTE sql_stmt;
processed := processed + 1;
END LOOP;
-- 7. Modify PROCEDURE owners (excluding procedures inside packages)
FOR obj_rec IN
SELECT n.nspname AS schemaname, p.proname AS procname,
pg_get_function_identity_arguments(p.oid) AS args
FROM pg_proc p JOIN pg_namespace n ON p.pronamespace = n.oid
WHERE n.nspname IN (SELECT rolname FROM pg_roles WHERE rolsuper = false)
AND EXISTS (SELECT 1 FROM information_schema.schemata s WHERE s.schema_name = n.nspname)
AND n.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast',
'polar_catalog', 'sys', 'cron', 'wmsys', 'polar_feature_utils',
'pg_bitmapindex', 'polar_dbms_stats', 'public')
AND n.nspname NOT LIKE 'pg_temp_%' AND n.nspname NOT LIKE 'pg_toast_temp_%'
AND nsppkgns = 0 AND p.prokind = 'p'
AND (SELECT rolname FROM pg_roles WHERE oid = p.proowner) != n.nspname
ORDER BY n.nspname, p.proname
LOOP
sql_stmt := format('ALTER PROCEDURE %I.%I(%s) OWNER TO %I',
obj_rec.schemaname, obj_rec.procname, obj_rec.args, obj_rec.schemaname);
RAISE NOTICE '%', sql_stmt;
EXECUTE sql_stmt;
processed := processed + 1;
END LOOP;
-- 8. Modify PACKAGE owners
FOR obj_rec IN
SELECT n.nspname AS schemaname, p.pkgname AS pkgname
FROM pg_pkg p JOIN pg_namespace n ON p.pkgnamespace = n.oid
WHERE n.nspname IN (SELECT rolname FROM pg_roles WHERE rolsuper = false)
AND EXISTS (SELECT 1 FROM information_schema.schemata s WHERE s.schema_name = n.nspname)
AND n.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast',
'polar_catalog', 'sys', 'cron', 'wmsys', 'polar_feature_utils',
'pg_bitmapindex', 'polar_dbms_stats', 'public')
AND (SELECT rolname FROM pg_roles WHERE oid = p.pkgowner) != n.nspname
ORDER BY n.nspname, p.pkgname
LOOP
sql_stmt := format('ALTER PACKAGE %I.%I OWNER TO %I',
obj_rec.schemaname, obj_rec.pkgname, obj_rec.schemaname);
RAISE NOTICE '%', sql_stmt;
EXECUTE sql_stmt;
processed := processed + 1;
END LOOP;
-- 9. Modify TYPE owners (user-defined composite types only)
FOR obj_rec IN
SELECT n.nspname AS schemaname, t.typname AS typename
FROM pg_type t JOIN pg_namespace n ON t.typnamespace = n.oid
WHERE n.nspname IN (SELECT rolname FROM pg_roles WHERE rolsuper = false)
AND EXISTS (SELECT 1 FROM information_schema.schemata s WHERE s.schema_name = n.nspname)
AND n.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast',
'polar_catalog', 'sys', 'cron', 'wmsys', 'polar_feature_utils',
'pg_bitmapindex', 'polar_dbms_stats', 'public')
AND n.nsppkgns = 0
AND t.typname NOT LIKE '\_%'
AND t.typtype IN ('c', 'b')
AND (t.typrelid = 0 OR EXISTS (SELECT 1 FROM pg_class c WHERE c.oid = t.typrelid AND c.relkind = 'c'))
AND (SELECT rolname FROM pg_roles WHERE oid = t.typowner) != n.nspname
ORDER BY n.nspname, t.typname
LOOP
sql_stmt := format('ALTER TYPE %I.%I OWNER TO %I',
obj_rec.schemaname, obj_rec.typename, obj_rec.schemaname);
RAISE NOTICE '%', sql_stmt;
EXECUTE sql_stmt;
processed := processed + 1;
END LOOP;
-- 10. Modify SYNONYM owners
FOR obj_rec IN
SELECT n.nspname AS schemaname, s.synname AS synname,
CASE WHEN n.nspname = 'public' THEN 'PUBLIC' ELSE n.nspname END AS new_owner
FROM pg_synonym s JOIN pg_namespace n ON s.synnamespace = n.oid
WHERE n.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast',
'polar_catalog', 'sys', 'cron', 'wmsys', 'polar_feature_utils',
'pg_bitmapindex', 'polar_dbms_stats')
AND n.nsppkgns = 0
AND (SELECT rolname FROM pg_roles WHERE oid = s.owner) !=
CASE WHEN n.nspname = 'public' THEN 'PUBLIC' ELSE n.nspname END
ORDER BY n.nspname, s.synname
LOOP
sql_stmt := format('ALTER SYNONYM %I.%I OWNER TO %I',
obj_rec.schemaname, obj_rec.synname, obj_rec.new_owner);
RAISE NOTICE '%', sql_stmt;
EXECUTE sql_stmt;
processed := processed + 1;
END LOOP;
RAISE NOTICE 'Total objects processed: %', processed;
END $$;
(Optional) Grant system privileges
System privileges are an advanced Oracle feature that primarily control DDL execution. In PolarDB, we recommend that you use a privileged account for DDL operations, so you generally do not need to migrate system privileges. If needed, run the following PL/SQL script in SQL*Plus to export system privilege GRANT statements from the DBA_SYS_PRIVS view to the grant_sys_priv.sql file, then run it in PolarDB.
-
The query includes all roles in GRANTEE (not only non-system roles) because Oracle system roles may also be granted privileges manually, which must also be migrated. The query also includes the PUBLIC virtual role, which represents all users.
-
Before you run this command, log on to the PolarDB console and enable the
polar_enable_system_privilegeparameter on the cluster Parameters page.
Oracle 12c and later
SET HEADING OFF
SET TRIMSPOOL ON
SET TRIMOUT ON
SET PAGESIZE 0
SET LINESIZE 2000
SET SERVEROUTPUT ON
SPOOL /my/path/to/grant_sys_priv.sql
BEGIN
FOR rec IN (
SELECT
'GRANT ' || PRIVILEGE || ' TO ' || GRANTEE ||
CASE WHEN ADMIN_OPTION = 'YES' THEN ' WITH ADMIN OPTION' END || ';' AS ddl_script
FROM DBA_SYS_PRIVS
WHERE GRANTEE IN (
SELECT USERNAME FROM DBA_USERS WHERE ORACLE_MAINTAINED = 'N'
UNION
SELECT ROLE FROM DBA_ROLES
UNION
SELECT 'PUBLIC' FROM DUAL
)
ORDER BY GRANTEE, PRIVILEGE
) LOOP
DBMS_OUTPUT.PUT_LINE(rec.ddl_script);
END LOOP;
END;
/
SPOOL OFF
EXIT
Oracle 11g
SET HEADING OFF
SET TRIMSPOOL ON
SET TRIMOUT ON
SET PAGESIZE 0
SET LINESIZE 2000
SET SERVEROUTPUT ON
SPOOL /my/path/to/grant_sys_priv.sql
BEGIN
FOR rec IN (
SELECT
'GRANT ' || PRIVILEGE || ' TO ' || GRANTEE ||
CASE WHEN ADMIN_OPTION = 'YES' THEN ' WITH ADMIN OPTION' END || ';' AS ddl_script
FROM DBA_SYS_PRIVS
WHERE GRANTEE IN (
SELECT USERNAME FROM DBA_USERS WHERE USERNAME NOT IN (
'SYS', 'SYSTEM', 'DBSNMP', 'SYSMAN', 'OUTLN',
'CTXSYS', 'MDSYS', 'ORDSYS', 'ORDDATA', 'ORDPLUGINS', 'SI_INFORMTN_SCHEMA',
'WMSYS', 'EXFSYS', 'LBACSYS', 'XDB', 'ANONYMOUS', 'XS$NULL',
'OLAPSYS', 'MDDATA', 'OWBSYS', 'OWBSYS_AUDIT',
'APEX_030200', 'APEX_040000', 'APEX_040100', 'APEX_040200', 'APEX_050000',
'APEX_PUBLIC_USER', 'FLOWS_FILES', 'FLOWS_030000', 'FLOWS_040000',
'SPATIAL_CSW_ADMIN_USR', 'SPATIAL_WFS_ADMIN_USR',
'DIP', 'ORACLE_OCM', 'APPQOSSYS', 'MGMT_VIEW', 'SCOTT', 'HR',
'TSMSYS', 'WKPROXY', 'WK_TEST', 'PERFSTAT', 'TRACESVR',
'GSMADMIN_INTERNAL', 'GSMCATUSER', 'GSMUSER', 'SYSBACKUP', 'SYSDG', 'SYSKM'
)
AND USERNAME NOT LIKE 'APEX\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'FLOWS\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'ORA\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'ORACLE\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'SYS\_%' ESCAPE '\'
UNION
SELECT ROLE FROM DBA_ROLES
UNION
SELECT 'PUBLIC' FROM DUAL
)
ORDER BY GRANTEE, PRIVILEGE
) LOOP
DBMS_OUTPUT.PUT_LINE(rec.ddl_script);
END LOOP;
END;
/
SPOOL OFF
EXIT
(Optional) Set default roles
Default roles are an advanced Oracle feature that control which role privileges a user has by default after logon. In PolarDB, users automatically load privileges of all granted roles at logon, which matches Oracle's default behavior. Therefore, you generally do not need to perform this migration step.
If needed, run the following PL/SQL script in SQL*Plus to export ALTER USER ... DEFAULT ROLE statements to the default_role.sql file, then run it in PolarDB. The script automatically determines:
-
If the user's default role count = 0, the script emits
ALTER USER ... DEFAULT ROLE NONE. -
If the user's default role count = total role count, the script emits
ALTER USER ... DEFAULT ROLE ALL. -
Otherwise, the script emits the specific role list.
Before you run this command, log on to the PolarDB console and enable the polar_enable_default_role parameter on the cluster Parameters page.
Oracle 12c and later
SET HEADING OFF
SET TRIMSPOOL ON
SET TRIMOUT ON
SET PAGESIZE 0
SET LINESIZE 2000
SET SERVEROUTPUT ON
SPOOL /my/path/to/default_role.sql
BEGIN
FOR rec IN (
WITH user_list AS (
SELECT ROLE AS name FROM DBA_ROLES WHERE ORACLE_MAINTAINED = 'N'
UNION
SELECT USERNAME AS name FROM DBA_USERS WHERE ORACLE_MAINTAINED = 'N'
),
role_stats AS (
SELECT
GRANTEE,
COUNT(*) AS total_roles,
SUM(CASE WHEN DEFAULT_ROLE = 'YES' THEN 1 ELSE 0 END) AS default_roles,
LISTAGG(CASE WHEN DEFAULT_ROLE = 'YES' THEN GRANTED_ROLE END, ', ')
WITHIN GROUP (ORDER BY GRANTED_ROLE) AS default_role_list
FROM DBA_ROLE_PRIVS
WHERE GRANTEE IN (SELECT name FROM user_list)
AND GRANTEE NOT IN ('PDBADMIN')
GROUP BY GRANTEE
)
SELECT
'ALTER USER ' || GRANTEE || ' DEFAULT ROLE ' ||
CASE
WHEN default_roles = 0 THEN 'NONE'
WHEN default_roles = total_roles THEN 'ALL'
ELSE default_role_list
END || ';' AS ddl_script
FROM role_stats
ORDER BY GRANTEE
) LOOP
DBMS_OUTPUT.PUT_LINE(rec.ddl_script);
END LOOP;
END;
/
SPOOL OFF
EXIT
Oracle 11g
SET HEADING OFF
SET TRIMSPOOL ON
SET TRIMOUT ON
SET PAGESIZE 0
SET LINESIZE 2000
SET SERVEROUTPUT ON
SPOOL /my/path/to/default_role.sql
BEGIN
FOR rec IN (
WITH user_list AS (
SELECT ROLE AS name FROM DBA_ROLES WHERE ROLE NOT IN (
'CONNECT', 'RESOURCE', 'DBA', 'SELECT_CATALOG_ROLE',
'EXECUTE_CATALOG_ROLE', 'DELETE_CATALOG_ROLE', 'EXP_FULL_DATABASE',
'IMP_FULL_DATABASE', 'LOGSTDBY_ADMINISTRATOR', 'RECOVERY_CATALOG_OWNER',
'SCHEDULER_ADMIN', 'HS_ADMIN_SELECT_ROLE', 'HS_ADMIN_EXECUTE_ROLE',
'HS_ADMIN_ROLE', 'GLOBAL_AQ_USER_ROLE', 'OEM_ADVISOR', 'OEM_MONITOR',
'MGMT_USER', 'DATAPUMP_EXP_FULL_DATABASE', 'DATAPUMP_IMP_FULL_DATABASE',
'ADM_PARALLEL_EXECUTE_TASK', 'GATHER_SYSTEM_STATISTICS',
'OPTIMIZER_PROCESSING_RATE', 'ACCESS_CATALOG_ROLE', 'JAVAUSERPRIV',
'JAVAIDPRIV', 'JAVASYSPRIV', 'JAVADEBUGPRIV', 'EJBCLIENT', 'JMXSERVER',
'JAVA_ADMIN', 'JAVA_DEPLOY', 'AUTHENTICATEDUSER', 'XDB_SET_INVOKER',
'XDB_WEBSERVICES', 'XDB_WEBSERVICES_WITH_PUBLIC', 'XDB_WEBSERVICES_OVER_HTTP',
'XDBADMIN', 'XDB_WEBSERVICES_OVER_HTTPS', 'CTXAPP', 'ORDADMIN',
'WM_ADMIN_ROLE', 'OLAP_USER', 'OLAP_DBA', 'OLAP_XS_ADMIN',
'CSW_USR_ROLE', 'WFS_USR_ROLE', 'SPATIAL_CSW_ADMIN',
'SPATIAL_WFS_ADMIN', 'LBAC_DBA', 'APEX_ADMINISTRATOR_ROLE',
'FLOWS_FILES_ROLE', 'AQ_ADMINISTRATOR_ROLE', 'AQ_USER_ROLE',
'CWM_USER', 'DBFS_ROLE', 'OLAPI_TRACE_USER', 'OWB$CLIENT',
'OWB_DESIGNCENTER_VIEW', 'OWB_USER'
)
AND ROLE NOT LIKE 'APEX\_%' ESCAPE '\'
AND ROLE NOT LIKE 'FLOWS\_%' ESCAPE '\'
AND ROLE NOT LIKE 'ORA\_%' ESCAPE '\'
AND ROLE NOT LIKE 'ORACLE\_%' ESCAPE '\'
AND ROLE NOT LIKE 'SYS\_%' ESCAPE '\'
UNION
SELECT USERNAME AS name FROM DBA_USERS WHERE USERNAME NOT IN (
'SYS', 'SYSTEM', 'DBSNMP', 'SYSMAN', 'OUTLN',
'CTXSYS', 'MDSYS', 'ORDSYS', 'ORDDATA', 'ORDPLUGINS', 'SI_INFORMTN_SCHEMA',
'WMSYS', 'EXFSYS', 'LBACSYS', 'XDB', 'ANONYMOUS', 'XS$NULL',
'OLAPSYS', 'MDDATA', 'OWBSYS', 'OWBSYS_AUDIT',
'APEX_030200', 'APEX_040000', 'APEX_040100', 'APEX_040200', 'APEX_050000',
'APEX_PUBLIC_USER', 'FLOWS_FILES', 'FLOWS_030000', 'FLOWS_040000',
'SPATIAL_CSW_ADMIN_USR', 'SPATIAL_WFS_ADMIN_USR',
'DIP', 'ORACLE_OCM', 'APPQOSSYS', 'MGMT_VIEW', 'SCOTT', 'HR',
'TSMSYS', 'WKPROXY', 'WK_TEST', 'PERFSTAT', 'TRACESVR',
'GSMADMIN_INTERNAL', 'GSMCATUSER', 'GSMUSER', 'SYSBACKUP', 'SYSDG', 'SYSKM'
)
AND USERNAME NOT LIKE 'APEX\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'FLOWS\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'ORA\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'ORACLE\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'SYS\_%' ESCAPE '\'
),
role_stats AS (
SELECT
GRANTEE,
COUNT(*) AS total_roles,
SUM(CASE WHEN DEFAULT_ROLE = 'YES' THEN 1 ELSE 0 END) AS default_roles,
LISTAGG(CASE WHEN DEFAULT_ROLE = 'YES' THEN GRANTED_ROLE END, ', ')
WITHIN GROUP (ORDER BY GRANTED_ROLE) AS default_role_list
FROM DBA_ROLE_PRIVS
WHERE GRANTEE IN (SELECT name FROM user_list)
AND GRANTEE NOT IN ('PDBADMIN')
GROUP BY GRANTEE
)
SELECT
'ALTER USER ' || GRANTEE || ' DEFAULT ROLE ' ||
CASE
WHEN default_roles = 0 THEN 'NONE'
WHEN default_roles = total_roles THEN 'ALL'
ELSE default_role_list
END || ';' AS ddl_script
FROM role_stats
ORDER BY GRANTEE
) LOOP
DBMS_OUTPUT.PUT_LINE(rec.ddl_script);
END LOOP;
END;
/
SPOOL OFF
EXIT
(Optional) Create PROFILEs
PROFILEs are an advanced Oracle feature for password complexity checks, expiration policies, and similar controls. In PolarDB, users and passwords are typically managed from the console, so you generally do not need to migrate PROFILEs.
If needed, run the following PL/SQL script in SQL*Plus to retrieve PROFILEs for all users. The script emits four files: profile_verify_functions.sql, create_profiles.sql, alter_default_profile.sql, and alter_user_profile.sql. Transfer the files to the PolarDB side and run them in order by using psql to migrate Oracle PROFILEs to PolarDB.
-
Password parameters only: The script migrates only PASSWORD-related parameters (
PASSWORD_LIFE_TIME,PASSWORD_REUSE_TIME,PASSWORD_REUSE_MAX,PASSWORD_VERIFY_FUNCTION,PASSWORD_GRACE_TIME,PASSWORD_LOCK_TIME, andFAILED_LOGIN_ATTEMPTS). Resource limits (such asSESSIONS_PER_USER,CPU_PER_SESSION, andCONNECT_TIME) are not migrated because the PolarDB kernel does not support them. -
System PROFILEs excluded:
ORA_CIS_PROFILE,ORA_STIG_PROFILE, andMONITORING_PROFILEare Oracle built-in PROFILEs and are not migrated. -
Built-in verify functions excluded:
ORA12C_VERIFY_FUNCTIONandORA12C_STIG_VERIFY_FUNCTIONare Oracle built-in functions; they are not exported because PolarDB already provides them. -
Execution order: Run the files in the order Step 1 → 2 → 3 → 4 because Step 2 may reference the verify functions created in Step 1.
Oracle 12c and later
-- ==================================================================
-- Step 1: Export password verify functions referenced by PROFILEs
-- Description: Query DBA_SOURCE to get the full definition of custom verify functions referenced by PROFILEs.
-- Excludes Oracle built-in functions (ORA12C_VERIFY_FUNCTION, ORA12C_STIG_VERIFY_FUNCTION).
-- ==================================================================
SET SERVEROUTPUT ON SIZE UNLIMITED
SET LINESIZE 32767
SET LONG 2000000000
SET LONGCHUNKSIZE 2000000000
SET PAGESIZE 0
SET FEEDBACK OFF
SET HEADING OFF
SPOOL profile_verify_functions.sql
SELECT 'CREATE OR REPLACE ' || LISTAGG(TEXT, CHR(10)) WITHIN GROUP (ORDER BY LINE) AS ddl_script
FROM DBA_SOURCE
WHERE NAME IN (
SELECT DISTINCT LIMIT
FROM DBA_PROFILES
WHERE RESOURCE_NAME = 'PASSWORD_VERIFY_FUNCTION'
AND LIMIT IS NOT NULL
AND LIMIT <> 'NULL'
AND LIMIT NOT IN ('ORA12C_VERIFY_FUNCTION', 'ORA12C_STIG_VERIFY_FUNCTION')
)
AND TYPE = 'FUNCTION'
AND OWNER = 'SYS'
GROUP BY NAME, TYPE, OWNER;
SPOOL OFF
-- ==================================================================
-- Step 2: Create non-DEFAULT PROFILEs
-- Description: Read password-related parameters from DBA_PROFILES and generate CREATE PROFILE statements.
-- Excludes system PROFILEs (DEFAULT, ORA_CIS_PROFILE, ORA_STIG_PROFILE, MONITORING_PROFILE).
-- Migrates only password policy parameters; resource limits are not migrated.
-- ==================================================================
SPOOL create_profiles.sql
SELECT DISTINCT 'CREATE PROFILE ' || PROFILE || ' LIMIT '
|| LISTAGG(RESOURCE_NAME || ' ' || LIMIT, ' ') WITHIN GROUP (ORDER BY RESOURCE_NAME)
|| ';' AS ddl_script
FROM DBA_PROFILES WHERE RESOURCE_NAME IN (
'PASSWORD_LIFE_TIME',
'PASSWORD_REUSE_TIME',
'PASSWORD_REUSE_MAX',
'PASSWORD_VERIFY_FUNCTION',
'PASSWORD_GRACE_TIME',
'PASSWORD_LOCK_TIME',
'FAILED_LOGIN_ATTEMPTS'
) AND PROFILE NOT IN ('DEFAULT', 'ORA_CIS_PROFILE', 'ORA_STIG_PROFILE', 'MONITORING_PROFILE')
GROUP BY PROFILE;
SPOOL OFF
-- ==================================================================
-- Step 3: Update the DEFAULT PROFILE
-- Description: The target already has a DEFAULT profile, so use ALTER PROFILE instead of CREATE.
-- ==================================================================
SPOOL alter_default_profile.sql
SELECT DISTINCT 'ALTER PROFILE DEFAULT LIMIT '
|| LISTAGG(RESOURCE_NAME || ' ' || LIMIT, ' ') WITHIN GROUP (ORDER BY RESOURCE_NAME)
|| ';' AS ddl_script
FROM DBA_PROFILES WHERE RESOURCE_NAME IN (
'PASSWORD_LIFE_TIME',
'PASSWORD_REUSE_TIME',
'PASSWORD_REUSE_MAX',
'PASSWORD_VERIFY_FUNCTION',
'PASSWORD_GRACE_TIME',
'PASSWORD_LOCK_TIME',
'FAILED_LOGIN_ATTEMPTS'
) AND PROFILE = 'DEFAULT'
GROUP BY PROFILE;
SPOOL OFF
-- ==================================================================
-- Step 4: Bind users to PROFILEs
-- Description: Migrate the user-profile binding for non-system source users to the target.
-- Filter: ORACLE_MAINTAINED = 'N' excludes system users.
-- ==================================================================
SPOOL alter_user_profile.sql
SELECT 'ALTER USER ' || USERNAME || ' PROFILE ' || PROFILE || ';' AS ddl_script
FROM DBA_USERS
WHERE PROFILE NOT IN ('ORA_CIS_PROFILE', 'ORA_STIG_PROFILE', 'MONITORING_PROFILE')
AND ORACLE_MAINTAINED = 'N'
ORDER BY USERNAME;
SPOOL OFF
Oracle 11g
Oracle 11g does not have the ORACLE_MAINTAINED column. Therefore, Step 4 uses a predefined list to filter system users. Steps 1, 2, and 3 are identical to the Oracle 12c and later version; only Step 4 differs.
-- ==================================================================
-- Steps 1-3: Identical to the Oracle 12c and later version. Not repeated here.
-- ==================================================================
-- ==================================================================
-- Step 4: Bind users to PROFILEs (Oracle 11g)
-- Description: Uses an explicit system user list instead of the ORACLE_MAINTAINED column.
-- ==================================================================
SPOOL alter_user_profile.sql
SELECT 'ALTER USER ' || USERNAME || ' PROFILE ' || PROFILE || ';' AS ddl_script
FROM DBA_USERS
WHERE PROFILE NOT IN ('ORA_CIS_PROFILE', 'ORA_STIG_PROFILE', 'MONITORING_PROFILE')
AND USERNAME NOT IN (
'SYS','SYSTEM','DBSNMP','SYSMAN','OUTLN',
'CTXSYS','MDSYS','ORDSYS','ORDDATA','ORDPLUGINS','SI_INFORMTN_SCHEMA',
'WMSYS','EXFSYS','LBACSYS','XDB','ANONYMOUS','XS$NULL',
'OLAPSYS','MDDATA',
'OWBSYS','OWBSYS_AUDIT',
'APEX_030200','APEX_040000','APEX_040100','APEX_040200','APEX_050000',
'APEX_PUBLIC_USER','FLOWS_FILES','FLOWS_030000','FLOWS_040000',
'SPATIAL_CSW_ADMIN_USR','SPATIAL_WFS_ADMIN_USR',
'DIP','ORACLE_OCM','APPQOSSYS','MGMT_VIEW','SCOTT','HR','TSMSYS',
'WKPROXY','WK_TEST','PERFSTAT','TRACESVR',
'GSMADMIN_INTERNAL','GSMCATUSER','GSMUSER','SYSBACKUP','SYSDG','SYSKM'
)
AND USERNAME NOT LIKE 'APEX\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'FLOWS\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'ORA\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'ORACLE\_%' ESCAPE '\'
AND USERNAME NOT LIKE 'SYS\_%' ESCAPE '\'
ORDER BY USERNAME;
SPOOL OFF