最近有个datapump跨数据库迁移数据时,提示”ORA-39002: invalid operation”错误, 排除过目录文件权限和语法兼容问题,后来发现是目标库的Timezone Version低于源库的TZ version. 需要升级目标库的TZ VERSION,这里简单记录该问题.
$ impdp xxx@xxx directory=xxx dumpfile=xxx.dmp logfile=xxx.log table_exists_action=replace Import: Release 18.0.0.0.0 - Production on Tue Mar 22 17:40:58 2022 Version 18.3.0.0.0 Copyright (c) 1982, 2018, Oracle and/or its affiliates. All rights reserved. Connected to: Oracle Database 18c Enterprise Edition Release 18.0.0.0.0 - Production ORA-39002: invalid operation
官方文档Oracle Database Globalization Support Guide 对应的版本, 4.7 Upgrading the Time Zone File and Timestamp with Time Zone Data 章节有记录如何升级,可以使用utltz_* Scripts或DBMS_DST Package 完成升级。
# cdb$root
SQL> SELECT * FROM v$timezone_file;
FILENAME VERSION CON_ID
-------------------- ---------- ----------
timezlrg_31.dat 31 0
SQL> alter session set container=pdbanbob;
Session altered.
SQL> SELECT * FROM v$timezone_file;
FILENAME VERSION CON_ID
-------------------- ---------- ----------
timezlrg_18.dat 18 0
SQL> col PROPERTY_VALUE for a30
SQL> col PROPERTY_NAME for a50
SQL> r
SELECT property_name, property_value
FROM database_properties
WHERE property_name LIKE 'DST_%'
ORDER BY property_name
PROPERTY_NAME PROPERTY_VALUE
-------------------------------------------------- ------------------------------
DST_PRIMARY_TT_VERSION 18
DST_SECONDARY_TT_VERSION 0
DST_UPGRADE_STATE NONE
SQL> SELECT * FROM v$timezone_file;
FILENAME VERSION CON_ID
-------------------- ---------- ----------
timezlrg_31.dat 31 0
SQL> alter session set container=pdbanbob;
Session altered.
SQL> SELECT * FROM v$timezone_file;
FILENAME VERSION CON_ID
-------------------- ---------- ----------
timezlrg_18.dat 18 0
SQL> col PROPERTY_VALUE for a30
SQL> col PROPERTY_NAME for a50
SQL> r
SELECT property_name, property_value
FROM database_properties
WHERE property_name LIKE 'DST_%'
ORDER BY property_name
PROPERTY_NAME PROPERTY_VALUE
-------------------------------------------------- ------------------------------
DST_PRIMARY_TT_VERSION 18
DST_SECONDARY_TT_VERSION 0
DST_UPGRADE_STATE NONE
SQL> SELECT DBMS_DST.get_latest_timezone_version FROM dual;
GET_LATEST_TIMEZONE_VERSION
---------------------------
31
1 Select con_id,name,value$ from containers(props$) where name='DST_PRIMARY_TT_VERSION'
2* order by 1
CON_ID NAME VALUE$
---------- ------------------------------ ----------
1 DST_PRIMARY_TT_VERSION 31
5 DST_PRIMARY_TT_VERSION 18
6 DST_PRIMARY_TT_VERSION 18
8 DST_PRIMARY_TT_VERSION 18
9 DST_PRIMARY_TT_VERSION 18
10 DST_PRIMARY_TT_VERSION 18
...
Note:
注意CDB是31,但是PDB 还是18,之前的升级并不完整。
解决方法
升级低版本的Timezone version
SQL> shutdown immediate SQL> startup upgrade SQL> exec dbms_dst.begin_upgrade(31) SQL> shutdown immediate SQL> startup
— for pdb
Updating the RDBMS DST version of the CDB will not change the RDBMS_DST version of the PDB’s in this CDB.
Updating the RDBMS DST version of a PDB will not change the RDBMS_DST version of the other PDB’s or the CDB.
When creating a new PDB the RDBMS DST version of new PDB is the RDBMS DST version of PDB$SEED.
The RDBMS DST version of PDB$SEED is the RDBMS_DST version at the CDB creation time (default is DSTv18 for 12.1.0.2 and 12.1.0.1).
The RDBMS DST version of PDB$SEED can currently not be updated.
From 12cR2 onwards, timezone upgrade scripts are included in the target ORACLE_HOME under rdbms/admin directory.
Then set the below to login to PDB.
alter session set container = <pdb_name>;
If pdb name is pdb1, then check below.
alter session set container = pdb1;
Perform the Prepare Window and Upgrade Window in PDB.
Prepare Window
$ cd $ORACLE_HOME/rdbms/admin SQL> Show con_name SQL> show con_id SQL> SQL> @utltz_countstats.sql SQL> @utltz_countstar.sql exec dbms_scheduler.purge_log; select count(*) from SYS.WRI$_OPTSTAT_HISTGRM_HISTORY; select count(*) from SYS.WRI$_OPTSTAT_HISTHEAD_HISTORY; -- check the data retention period of the stats -- the default value is 31 select systimestamp - dbms_stats.get_stats_history_availability from dual; -- disable stats retention exec dbms_stats.alter_stats_history_retention(0); -- remove all the stats exec DBMS_STATS.PURGE_STATS(systimestamp); -- check the result of the purge operation select count(*) from SYS.WRI$_OPTSTAT_HISTGRM_HISTORY; select count(*) from SYS.WRI$_OPTSTAT_HISTHEAD_HISTORY; exec dbms_stats.alter_stats_history_retention(31);
Upgrade Window
Run the utltz_upg_check.sql script from the $ORACLE_HOME directory: spool utltz_upg_check.log @utltz_upg_check.sql spool off
Run the utltz_upg_apply.sql script from the $ORACLE_HOME directory after the utltz_upg_check.sql script is executed successfully: This script utltz_upg_apply.sql will shutdown and bring up the database two times.
spool utltz_upg_apply.log @utltz_upg_apply.sql spool off