暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

【DB宝73】Oracle中使用包FY_Recover_Data.pck来恢复truncate误操作的表

DB宝 2021-10-12
567

目录

    一、简介
    二、实验环境介绍
    三、 实验代码
    四、实验过程
    4.1、准备数据
    4.2、执行误操作
    4.3、开始恢复
    4.4、清理临时数据
    五、附录:包FY_Recover_Data的内容

    一、简介

    之前整理的内容:http://blog.itpub.net/26736162/viewspace-2082965/

    误操作执行truncate后的恢复方法很多,这里再次介绍fy_recover_data包,由大师Fuyunca开发。该包采用纯plsql语句恢复被truncate掉的表,操作比较简单,包的内容参考本文后边的附录部分。

    Fy_Recover_Data是利用Oracle表扫描机制、数据嫁接机制恢复TRUNCATE或者损坏数据的工具包。由纯PLSQL编写,原理图如下:

    二、实验环境介绍

    项目db
    db 类型单实例
    db version19.3.0.0
    db 存储FS
    主机IP地址/hosts配置192.168.66.35
    OS版本及kernel版本CentOS 7.6
    归档模式Archive Mode
    ORACLE_SIDlhrsdb

    三、 实验代码

     1-- 准备数据 2set timing on; 3set serveroutput on; 4create table lhr.LHRTB_210702    as SELECT * FROM dba_objects; 5SELECT COUNT(1FROM   lhr.LHRTB_210702; 6INSERT INTO lhr.LHRTB_210702 SELECT * FROM lhr.LHRTB_210702; 7INSERT INTO lhr.LHRTB_210702 SELECT * FROM lhr.LHRTB_210702; 8commit; 9SELECT COUNT(1FROM   lhr.LHRTB_210702;10SELECT d.BYTES/1024/1024 FROM dba_segments d WHERE d.segment_name ='LHRTB_210702';11truncate table lhr.LHRTB_210702;12SELECT COUNT(1FROM   lhr.LHRTB_210702;131415-- 数据已经被truncate掉了,下边我们来恢复16@/tmp/FY_Recover_Data.pck17exec fy_recover_data.recover_truncated_table('LHR','LHRTB_210702');18SELECT COUNT(1FROM   lhr.LHRTB_210702$$;19alter table lhr.LHRTB_210702 nologging;20insert /*+append*/ into lhr.LHRTB_210702 select * from lhr.LHRTB_210702$$;21commit;22alter table lhr.LHRTB_210702 logging;23SELECT COUNT(1FROM   lhr.LHRTB_210702;242526-- 清理数据27drop tablespace   FY_REC_DATA  including contents and datafiles;28drop tablespace   FY_RST_DATA  including contents and datafiles;

    四、实验过程

    4.1、准备数据

     1Microsoft Windows [版本 10.0.17134.765] 2(c) 2018 Microsoft Corporation。保留所有权利。 3 4C:\Users\lhrxxt>sqlplus sys/lhr@192.168.66.35:11521/lhrsdb as sysdba 5 6SQL*Plus: Release 12.1.0.2.0 Production on Fri Jul 2 16:00:36 2021 7 8Copyright (c) 19822014, Oracle.  All rights reserved. 91011Connected to:12Oracle Database 19Enterprise Edition Release 19.0.0.0.0 - Production1314SYS@192.168.66.35:11521/lhrsdb> set timing on;15SYS@192.168.66.35:11521/lhrsdb> set serveroutput on;16SYS@192.168.66.35:11521/lhrsdb>17SYS@192.168.66.35:11521/lhrsdb> select * from v$version;1819BANNER                                                                           BANNER_FULL                                                                                                                                      BANNER_LEGACY                                                                     CON_ID20-------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ----------21Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production           Oracle Database 19Enterprise Edition Release 19.0.0.0.0 - Production                                                                                   Oracle Database 19Enterprise Edition Release 19.0.0.0.0 - Production                    022                                                                                 Version 19.3.0.0.0232425Elapsed: 00:00:00.15262728SYS@192.168.66.35:11521/lhrsdb> create user lhr identified by lhr;2930User created.3132Elapsed: 00:00:00.2633SYS@192.168.66.35:11521/lhrsdb> grant dba to lhr;3435Grant succeeded.3637Elapsed: 00:00:00.1238SYS@192.168.66.35:11521/lhrsdb>39SYS@192.168.66.35:11521/lhrsdb> create table lhr.LHRTB_210702    as SELECT * FROM dba_objects;4041Table created.4243Elapsed: 00:00:01.8344SYS@192.168.66.35:11521/lhrsdb>45SYS@192.168.66.35:11521/lhrsdb> INSERT INTO lhr.LHRTB_210702 SELECT * FROM lhr.LHRTB_210702;464772690 rows created.4849Elapsed: 00:00:00.6750SYS@192.168.66.35:11521/lhrsdb>51SYS@192.168.66.35:11521/lhrsdb> INSERT INTO lhr.LHRTB_210702 SELECT * FROM lhr.LHRTB_210702;5253145380 rows created.5455Elapsed: 00:00:00.9156SYS@192.168.66.35:11521/lhrsdb> commit;5758Commit complete.5960Elapsed: 00:00:00.1161SYS@192.168.66.35:11521/lhrsdb> SELECT COUNT(1FROM   lhr.LHRTB_210702;6263  COUNT(1)64----------65    2907606667Elapsed: 00:00:00.1968SYS@192.168.66.35:11521/lhrsdb>69SYS@192.168.66.35:11521/lhrsdb> SELECT d.BYTES/1024/1024 FROM dba_segments d WHERE d.segment_name ='LHRTB_210702';7071D.BYTES/1024/102472-----------------73               457475Elapsed: 00:00:00.60

    4.2、执行误操作

     1SYS@192.168.66.35:11521/lhrsdb> truncate table lhr.LHRTB_210702; 2 3Table truncated. 4 5Elapsed: 00:00:00.59 6SYS@192.168.66.35:11521/lhrsdb> 7SYS@192.168.66.35:11521/lhrsdb> SELECT COUNT(1FROM   lhr.LHRTB_210702; 8 9  COUNT(1)10----------11         01213Elapsed: 00:00:00.18

    4.3、开始恢复

     1SYS@192.168.66.35:11521/lhrsdb> @D:\FY_Recover_Data.pck 2 3Package created. 4 5Elapsed: 00:00:00.29 6 7Package body created. 8 9Elapsed: 00:00:00.6710SYS@192.168.66.35:11521/lhrsdb> select * from v$tablespace;1112       TS# NAME                           INC BIG FLA ENC     CON_ID13---------- ------------------------------ --- --- --- --- ----------14         1 SYSAUX                         YES NO  YES              015         0 SYSTEM                         YES NO  YES              016         2 UNDOTBS1                       YES NO  YES              017         4 USERS                          YES NO  YES              018         3 TEMP                           NO  NO  YES              01920Elapsed: 00:00:00.1621SYS@192.168.66.35:11521/lhrsdb>22SYS@192.168.66.35:11521/lhrsdb> exec fy_recover_data.recover_truncated_table('LHR','LHRTB_210702');2316:03:26: New Directory Name: FY_DATA_DIR2416:03:26: Recover Tablespace: FY_REC_DATA; Data File: FY_REC_DATA.DAT2516:03:26: Restore Tablespace: FY_RST_DATA; Data File: FY_RST_DATA.DAT2616:03:27: Recover Table: LHR.LHRTB_210702$2716:03:27: Restore Table: LHR.LHRTB_210702$$2816:03:49: Copy file of Recover Tablespace: FY_REC_DATA_COPY.DAT2916:03:49begin to recover table LHR.LHRTB_2107023016:03:50New Directory Name: TMP_HF_DIR3116:03:52: Recovering data in datafile /opt/oracle/oradata/LHRSDB/users01.dbf3216:03:52Use existing Directory Name: TMP_HF_DIR3316:06:255662 truncated data blocks found.3416:06:25290760 records recovered in backup table LHR.LHRTB_210702$$3516:06:25: Total: 5662 truncated data blocks found.3616:06:25: Total: 290760 records recovered in backup table LHR.LHRTB_210702$$3716:06:25Recovery completed.3816:06:25Data has been recovered to LHR.LHRTB_210702$$3940PL/SQL procedure successfully completed.4142Elapsed: 00:02:59.2743SYS@192.168.66.35:11521/lhrsdb> SELECT COUNT(1FROM   lhr.LHRTB_210702$$;4445  COUNT(1)46----------47    2907604849Elapsed: 00:00:00.5250SYS@192.168.66.35:11521/lhrsdb>51SYS@192.168.66.35:11521/lhrsdb> alter table lhr.LHRTB_210702 nologging;5253Table altered.5455Elapsed: 00:00:00.2556SYS@192.168.66.35:11521/lhrsdb>57SYS@192.168.66.35:11521/lhrsdb> insert /*+append*/ into lhr.LHRTB_210702 select * from lhr.LHRTB_210702$$;5859290760 rows created.6061Elapsed: 00:00:01.9962SYS@192.168.66.35:11521/lhrsdb> commit;6364Commit complete.6566Elapsed: 00:00:00.9167SYS@192.168.66.35:11521/lhrsdb> alter table lhr.LHRTB_210702 logging;6869Table altered.7071Elapsed: 00:00:00.1172SYS@192.168.66.35:11521/lhrsdb>73SYS@192.168.66.35:11521/lhrsdb> SELECT COUNT(1FROM   lhr.LHRTB_210702;7475  COUNT(1)76----------77    2907607879Elapsed: 00:00:00.25

    4.4、清理临时数据

      1SYS@192.168.66.35:11521/lhrsdb> select * from v$tablespace;  2  3       TS# NAME                           INC BIG FLA ENC     CON_ID  4---------- ------------------------------ --- --- --- --- ----------  5         1 SYSAUX                         YES NO  YES              0  6         0 SYSTEM                         YES NO  YES              0  7         2 UNDOTBS1                       YES NO  YES              0  8         4 USERS                          YES NO  YES              0  9         3 TEMP                           NO  NO  YES              0 10         6 FY_REC_DATA                    YES NO  YES              0 11         7 FY_RST_DATA                    YES NO  YES              0 12 137 rows selected. 14 15SYS@192.168.66.35:11521/lhrsdb> set pagesize 9999 line 9999 16SYS@192.168.66.35:11521/lhrsdb> col TS_Name format a30 17SYS@192.168.66.35:11521/lhrsdb> col PDBNAME format a15 18SYS@192.168.66.35:11521/lhrsdb> col TS_NAME format a20 19SYS@192.168.66.35:11521/lhrsdb> col LOGGING format a10 20SYS@192.168.66.35:11521/lhrsdb> WITH wt1 AS 21  2   (SELECT ts.TABLESPACE_NAME, 22  3           df.all_bytes, 23  4           decode(df.TYPE, 24  5                  'D', 25  6                  nvl(fs.FREESIZ, 0), 26  7                  'T', 27  8                  df.all_bytes - nvl(fs.FREESIZ, 0)) FREESIZ, 28  9           df.MAXSIZ, 29 10           ts.BLOCK_SIZE, 30 11           ts.LOGGING, 31 12           ts.FORCE_LOGGING, 32 13           ts.CONTENTS, 33 14           ts.EXTENT_MANAGEMENT, 34 15           ts.SEGMENT_SPACE_MANAGEMENT, 35 16           ts.RETENTION, 36 17           ts.DEF_TAB_COMPRESSION, 37 18           df.ts_df_count 38 19    FROM   dba_tablespaces ts, 39 20           (SELECT 'D' TYPE, 40 21                   TABLESPACE_NAME, 41 22                   COUNT(*) ts_df_count, 42 23                   SUM(BYTES) all_bytes, 43 24                   SUM(decode(MAXBYTES, 0BYTES, MAXBYTES)) MAXSIZ 44 25            FROM   dba_data_files d 45 26            GROUP  BY TABLESPACE_NAME 46 27            UNION ALL 47 28            SELECT 'T', 48 29                   TABLESPACE_NAME, 49 30                   COUNT(*) ts_df_count, 50 31                   SUM(BYTES) all_bytes, 51 32                   SUM(decode(MAXBYTES, 0BYTES, MAXBYTES)) 52 33            FROM   dba_temp_files d 53 34            GROUP  BY TABLESPACE_NAME) df, 54 35           (SELECT TABLESPACE_NAME, 55 36                   SUM(BYTES) FREESIZ 56 37            FROM   dba_free_space 57 38            GROUP  BY TABLESPACE_NAME 58 39            UNION ALL 59 40            SELECT tablespace_name, 60 41                   SUM(d.BLOCK_SIZE * a.BLOCKS) bytes 61 42            FROM   gv$sort_usage   a, 62 43                   dba_tablespaces d 63 44            WHERE  a.tablespace = d.tablespace_name 64 45            GROUP  BY tablespace_name) fs 65 46    WHERE  ts.TABLESPACE_NAME = df.TABLESPACE_NAME 66 47    AND    ts.TABLESPACE_NAME = fs.TABLESPACE_NAME(+)) 67 48  SELECT (SELECT A.TS# 68 49          FROM   V$TABLESPACE A 69 50          WHERE  A.NAME = UPPER(t.TABLESPACE_NAME)) TS#, 70 51         t.TABLESPACE_NAME TS_Name, 71 52         round(t.all_bytes / 1024 / 1024) ts_size_M, 72 53         round(t.freesiz / 1024 / 1024) Free_Size_M, 73 54         round((t.all_bytes - t.FREESIZ) / 1024 / 1024) Used_Size_M, 74 55         round((t.all_bytes - t.FREESIZ) * 100 / t.all_bytes, 3) Used_per, 75 56         round(MAXSIZ / 1024 / 1024/10243) MAX_Size_g, 76 57         round(decode(MAXSIZ, 0, to_number(NULL), (t.all_bytes - FREESIZ)) * 100 / 77 58               MAXSIZ, 78 59               3) USED_per_MAX, 79 60         round(t.BLOCK_SIZE) BLOCK_SIZE, 80 61         t.LOGGING, 81 62         t.ts_df_count 82 63  FROM   wt1 t 83 64  UNION ALL 84 65  SELECT to_number('') TS#, 85 66         'ALL TS:' TS_Name, 86 67         round(SUM(t.all_bytes) / 1024 / 10243) ts_size_M, 87 68         round(SUM(t.freesiz) / 1024 / 1024) Free_Size_m, 88 69         round(SUM(t.all_bytes - t.FREESIZ) / 1024 / 1024) Used_Size_M, 89 70         round(SUM(t.all_bytes - t.FREESIZ) * 100 / SUM(t.all_bytes), 3) Used_per, 90 71         round(SUM(MAXSIZ) / 1024 / 1024/1024) MAX_Size, 91 72         to_number(''"USED,% of MAX Size", 92 73         to_number('') BLOCK_SIZE, 93 74         '' LOGGING, 94 75         to_number('') ts_df_count 95 76  FROM   wt1 t 96 77  order by TS# 97 78  ; 98 99       TS# TS_NAME               TS_SIZE_M FREE_SIZE_M USED_SIZE_M   USED_PER MAX_SIZE_G USED_PER_MAX BLOCK_SIZE LOGGING    TS_DF_COUNT100---------- -------------------- ---------- ----------- ----------- ---------- ---------- ------------ ---------- ---------- -----------101         0 SYSTEM                      910           4         906      99.54         32        2.764       8192 LOGGING              1102         1 SYSAUX                      670          30         640     95.476         32        1.952       8192 LOGGING              1103         2 UNDOTBS1                    345         271          74     21.413         32         .225       8192 LOGGING              1104         3 TEMP                         33          27           6     18.182         32         .018       8192 NOLOGGING            1105         4 USERS                       344           2         341     99.291         32        1.042       8192 LOGGING              1106         6 FY_REC_DATA                   0           0           0        100          0          100       8192 LOGGING              1107         7 FY_RST_DATA                  57           3          54     95.154         32         .165       8192 LOGGING              1108           ALL TS:                2358.625         338        2021     85.678        1921091108 rows selected.111112Elapsed: 00:00:00.59113SYS@192.168.66.35:11521/lhrsdb>114SYS@192.168.66.35:11521/lhrsdb> drop tablespace   FY_REC_DATA  including contents and datafiles;115116Tablespace dropped.117118Elapsed: 00:00:12.01119SYS@192.168.66.35:11521/lhrsdb>120SYS@192.168.66.35:11521/lhrsdb>121SYS@192.168.66.35:11521/lhrsdb> drop tablespace   FY_RST_DATA  including contents and datafiles;122123Tablespace dropped.124125Elapsed: 00:00:11.43126SYS@192.168.66.35:11521/lhrsdb> drop table lhr.LHRTB_210702$$;127drop table lhr.LHRTB_210702$$128               *129ERROR at line 1:130ORA-00942table or view does not exist131132133Elapsed: 00:00:00.15134SYS@192.168.66.35:11521/lhrsdb>

    总体而言用fy_recover_data包是非常好的,fy_recover_data可以恢复truncate的数据,但不能恢复drop的数据。

    五、附录:包FY_Recover_Data的内容

       1create or replace package sys.FY_Recover_Data is   2  ---------------------------------------------------------------------------   3  -- WWW.HelloDBA.COM                                                     ---   4  -- Created By: Fuyuncat                                                 ---   5  -- Created Date: 08/08/2012                                             ---   6  -- Email: Fuyuncat@gmail.com                                            ---   7  -- Copyright (c), 2014, WWW.HelloDBA.COM All rights reserved.           ---   8  -- Latest Version: http://www.HelloDBA.com/download/FY_Recover_Data.zip ---   9  --                                                                      ---  10  -- Update Logs                                                          ---  11  -- 15/08/2012, Fuyuncat:                                                ---  12  --   1. Fixed Bug in Clean_Up_Ts (Not change TS status correctly)        ---  13  --   2. Added Exception Handle when Restore Data                        ---  14  --   3. Added Parameter in recover_table,                               ---  15  --            to balance Fault Tolerance and Performance                ---  16  --                                                                      ---  17  -- 16/08/2012, Fuyuncat:                                                ---  18  --   1. Enhanced corrupted block processing, get rows as possilbe       ---  19  --                                                                      ---  20  -- 17/08/2012, Fuyuncat:                                                ---  21  --   1. Omit the LOB columns raised ORA-22922 exception                 ---  22  --                                                                      ---  23  -- 20/08/2012, Fuyuncat:                                                ---  24  --   1. Omit the LOB columns via db link                                ---  25  --                                                                      ---  26  -- 22/08/2012, Fuyuncat:                                                ---  27  --   1. Updated logging and tracing interface                           ---  28  --                                                                      ---  29  -- 19/02/2014, Fuyuncat:                                                ---  30  --   1. Temp Restore and Recover tablespace                      ---  31  --      will be created on temp folder                                  ---  32  --   2. Handle tablespace has files located at diff folders             ---  33  --   3. Handle tables on ASM                                            ---  34  --                                                                      ---  35  -- 05/03/2014, Fuyuncat:                                                ---  36  --   1. Fixed bugs                                                      ---  37  --   2. Use existing dirctory if applicable                             ---  38  --   3. Recover data from offline files                                 ---  39  ---------------------------------------------------------------------------  40  41  type r_cursor is REF CURSOR;  42  type o_fileprop is record(  43    file#   number,  44    status$ number);  45  type t_fileprops is table of o_fileprop;  46  47  /************************************************************************  48  ** recover truncated table  49  **  50  ** tgtowner: Owner of Target Table to be recovered;  51  ** tgttable: Name of Target Table to be recovered;  52  ** datapath: Absolute path of Data Files;  53  ** fbks: block number to be filled in recovery table;  54  ** offline_files: Offline data files that data should be recovered from;  55  **    foramt: full_path_file1;full_path_file2...;  56  ************************************************************************/  57  procedure recover_truncated_table(tow           varchar2,  58                                    ttb           varchar2,  59                                    fbks          number default 1,  60                                    tmppath       varchar2 default null,  61                                    offline_files varchar2 default null);  62  63  /************************************************************************  64  ** dump a block in raw, for testing  65  **  66  ** hdfile: Data file name;  67  ** srcdir: data file directory  68  ** blknb: block number to be dumped;  69  ** blksz: block size;  70  ************************************************************************/  71  procedure dump_seg_block_raw(hdfile varchar2,  72                               srcdir varchar2,  73                               blknb  number,  74                               blksz  number default 8192);  75  /*  76    procedure test_chain(filename varchar2,  77                         blknum number,  78                         startpos number,  79                         repcont raw,  80                         srcdir varchar2 default 'FY_DATA_DIR');  81  */  82  /************************************************************************  83  ** Set Initial parameters  84  **  85  ** tracing: trace the process for debug;  86  ** logging: show logging information;  87  ** repobjid: replace the data object id wiht the recover table data object id;  88  ************************************************************************/  89  procedure init_set(tracing  boolean default true,  90                     logging  boolean default true,  91                     repobjid boolean default true);  92end FY_Recover_Data;  93/  94create or replace package body sys.FY_Recover_Data is  95  ---------------------------------------------------------------------------  96  -- WWW.HelloDBA.COM                                                     ---  97  -- Created By: Fuyuncat                                                 ---  98  -- Created Date: 08/08/2012                                             ---  99  -- Email: Fuyuncat@gmail.com                                            --- 100  -- Copyright (c), 2014, WWW.HelloDBA.COM All rights reserved.            --- 101  -- Latest Version: http://www.HelloDBA.com/download/FY_Recover_Data.zip   --- 102  --------------------------------------------------------------------------- 103 104  s_tracing  boolean := false; 105  s_logging  boolean := true; 106  s_repobjid boolean := false; 107 108  procedure init_set(tracing  boolean default true, 109                     logging  boolean default true, 110                     repobjid boolean default true) as 111  begin 112    s_tracing  := tracing; 113    s_logging  := logging; 114    s_repobjid := repobjid; 115  end; 116 117  procedure trace(msg varchar2) as 118  begin 119    if s_tracing then 120      dbms_output.put_line(to_char(sysdate'HH24:MI:SS') || ': ' || msg); 121    end if; 122  end; 123 124  procedure log(msg varchar2) as 125  begin 126    if s_logging then 127      dbms_output.put_line(to_char(sysdate'HH24:MI:SS') || ': ' || msg); 128    end if; 129  end; 130 131  function d2r(dig varchar2, len number default 0) return raw is 132  begin 133    --trace('[d2r] hextoraw(lpad(trim(to_char('||dig||', ''XXXXXXXX'')),'||len||',''0''))'); 134    return hextoraw(lpad(trim(to_char(dig, 'XXXXXXXX')), len'0')); 135  end; 136 137  /************************************************************************ 138  ** Copy file 139  ** 140  ** srcdir: Directory of Source File; 141  ** srcfile: Source File Name; 142  ** dstdir: Directory of Destination File; 143  ** dstfile: Destination File Name; 144  ************************************************************************/ 145  procedure copy_file(srcdir  varchar2, 146                      srcfile varchar2, 147                      dstdir  varchar2, 148                      dstfile in out varchar2) as 149    --p_srcdir varchar2(255) := upper(srcdir); 150    --p_srcfile varchar2(255) := upper(srcfile); 151    --p_dstdir varchar2(255) := upper(dstdir); 152    --p_dstfile varchar2(255) := upper(dstfile); 153    p_srcdir    varchar2(255) := srcdir; 154    p_srcfile   varchar2(255) := srcfile; 155    p_dstdir    varchar2(255) := dstdir; 156    p_dstfile   varchar2(255) := dstfile; 157    file_copied boolean := false; 158    retries     pls_integer := 0; 159  begin 160    if dstdir is null then 161      p_dstdir := p_srcdir; 162    end if; 163    if dstfile is null then 164      p_dstfile := p_srcfile || '$'; 165      dstfile   := p_dstfile; 166    end if; 167    while not file_copied loop 168      begin 169        trace('[copy_file] begin copy file: ' || p_srcdir || '\' || 170              p_srcfile || ' => ' || p_dstdir || '\' || p_dstfile); --' 171        DBMS_FILE_TRANSFER.copy_file(p_srcdir, 172                                     p_srcfile, 173                                     p_dstdir, 174                                     p_dstfile); 175        trace('[copy_file] completed.'); 176        file_copied := true; 177      exception 178        when others then 179          -- file already exists 180          if sqlcode = -19504 and 181             instr(dbms_utility.format_error_stack, 'ORA-27038') > 0 and 182             retries < 10 then 183            trace('[copy_file] file ' || p_dstdir || '\' || p_dstfile || 184                  ' exists, rename to ' || dstfile || retries); 185            retries     := retries + 1; 186            p_dstfile   := dstfile || retries; 187            file_copied := false; 188          else 189            --log(dbms_utility.format_error_backtrace); 190            file_copied := true; 191            raise; 192          end if; 193      end; 194    end loop; 195    dstfile := p_dstfile; 196  end; 197 198  /************************************************************************ 199  ** Remove file 200  ** 201  ** dir: Directory of the File; 202  ** file: File to be removed; 203  ************************************************************************/ 204  procedure remove_file(dir varchar2, file varchar2) as 205  begin 206    trace('[remove_file] Begin to remove file ' || dir || '/' || file); 207    utl_file.fremove(dir, file); 208    trace('[remove_file] ' || dir || '/' || file || ' has been removed.'); 209  end; 210 211  function gen_table_name(tgttable varchar2, 212                          plus     varchar2 default '', 213                          genowner varchar2 default user) return varchar2 as 214    gentab varchar2(30); 215  begin 216    select upper(tgttable || plus || surfix) 217      into gentab 218      from (select surfix 219              from (select null surfix 220                      from dual 221                    union all 222                    select level surfix 223                      from dual 224                    connect by level <= 255) 225             where not exists 226             (select 1 227                      from dba_tables 228                     where owner = genowner 229                       and table_name = upper(tgttable || plus || surfix)) 230             order by surfix nulls first) 231     where rownum <= 1; 232    return gentab; 233  end; 234 235  function gen_file_name(tgtfile varchar2, plus varchar2 default '') 236    return varchar2 as 237    genfile varchar2(30); 238    slash   char(1); 239  begin 240    select decode(instr(platform_name, 'Windows'), 0, '/', '\') 241      into slash 242      from v_$database 243     where rownum <= 1; 244    select tgtfile || plus || surfix || '.DAT' 245      into genfile 246      from (select surfix 247              from (select null surfix 248                      from dual 249                    union all 250                    select level surfix 251                      from dual 252                    connect by level <= 255) 253             where not exists (select 1 254                      from dba_data_files 255                     where file_name like '%' || slash || tgtfile || plus || 256                           surfix || '.DAT') 257             order by surfix nulls first) 258     where rownum <= 1; --' 259    return genfile; 260  end; 261 262  function gen_ts_name(tgtts varchar2, plus varchar2 default '') 263    return varchar2 as 264    gents varchar2(30); 265  begin 266    select tgtts || plus || surfix 267      into gents 268      from (select surfix 269              from (select null surfix 270                      from dual 271                    union all 272                    select level surfix 273                      from dual 274                    connect by level <= 255) 275             where not exists 276             (select 1 277                      from dba_tablespaces 278                     where tablespace_name = tgtts || plus || surfix) 279             order by surfix nulls first) 280     where rownum <= 1; 281    return gents; 282  end; 283 284  procedure create_directory(path varchar2, dir in out varchar2) as 285    exists_path pls_integer; 286    exists_dir  varchar2(256); 287    slash       char(1); 288  begin 289    select decode(instr(platform_name, 'Windows'), 0'/''\') 290      into slash 291      from v_$database 292     where rownum <= 1; 293    -- windows 294    if slash = '\' then 295      select count(1), max(directory_name) 296        into exists_path, exists_dir 297        from dba_directories 298       where owner = user 299         and upper(directory_path) || 300             decode(substr(directory_path, length(directory_path)), 301                    slash, 302                    '', 303                    slash) = 304             upper(path) || 305             decode(substr(path, length(path)), slash, '', slash); 306    else 307      -- linux/unix 308      select count(1), max(directory_name) 309        into exists_path, exists_dir 310        from dba_directories 311       where owner = user 312         and directory_path || 313             decode(substr(directory_path, length(directory_path)), 314                    slash, 315                    '', 316                    slash) = 317             path || decode(substr(path, length(path)), slash, '', slash); 318    end if; 319    trace('[create_directory] Exists directory number ' || exists_path); 320    if exists_path = 0 then 321      select dir || surfix 322        into dir 323        from (select surfix 324                from (select null surfix 325                        from dual 326                      union all 327                      select level surfix 328                        from dual 329                      connect by level <= 255) 330               where not exists 331               (select 1 332                        from dba_directories 333                       where directory_name = dir || surfix) 334               order by surfix nulls first) 335       where rownum <= 1; 336      log('New Directory Name' || dir); 337      execute immediate 'create directory ' || dir || ' as ''' || path || ''''; 338    else 339      dir := exists_dir; 340      log('Use existing Directory Name' || dir); 341    end if; 342  end; 343 344  procedure replace_segmeta_in_file(tmpdir          varchar2, 345                                    tmpcopyf        varchar2, 346                                    dstdir          varchar2, 347                                    dstfile         in out varchar2, 348                                    dstisfilesystem boolean, 349                                    tgtobjid        number, 350                                    newobjid        number, 351                                    dtail           raw, 352                                    addpos          number, 353                                    addinfo         raw, 354                                    blksz           number default 8192, 355                                    endianess       number default 1) as 356    bfr           utl_file.file_type; 357    bfw           utl_file.file_type; 358    hsz           number := 24; 359    objr          raw(4); 360    objn          number; 361    dhead         raw(32); 362    dbody         raw(32767); 363    nbody         raw(32767); 364    p_tmpdir      varchar2(255) := tmpdir; 365    p_tmpcopyf    varchar2(255) := tmpcopyf; 366    p_dstdir      varchar2(255) := dstdir; 367    p_tmpdstfile  varchar2(255); 368    p_finaldstdir varchar2(255); 369  begin 370    if p_dstdir is null then 371      p_dstdir := p_tmpdir; 372    end if; 373    trace('[replace_objid_in_file] replace object id in ' || tmpdir || '\' || 374          tmpcopyf || ' [' || tgtobjid || ' => ' || newobjid || ']'); --' 375    if not dstisfilesystem then 376      p_tmpdstfile := gen_file_name(dstfile, ''); 377      copy_file(dstdir, dstfile, p_tmpdir, p_tmpdstfile); 378      p_finaldstdir := p_tmpdir; 379    else 380      p_tmpdstfile  := dstfile; 381      p_finaldstdir := p_dstdir; 382    end if; 383    bfr := utl_file.fopen(p_tmpdir, p_tmpcopyf, 'RB'); 384    bfw := utl_file.fopen(p_finaldstdir, p_tmpdstfile, 'WB'); 385    while true loop 386      begin 387        nbody := ''; 388        utl_file.get_raw(bfr, dhead, hsz); 389        exit when dhead is null; 390        utl_file.get_raw(bfr, dbody, blksz - hsz); 391        --objr := hextoraw(substrb(rawtohex(dbody), 1, 8)); 392        objr := utl_raw.substr(dbody, 1, 4); 393        if endianess > 0 then 394          objn := to_number(rawtohex(utl_raw.reverse(objr)), 'XXXXXXXX'); 395        else 396          objn := to_number(rawtohex(objr), 'XXXXXXXX'); 397        end if; 398        -- replace data object id with the recover object id 399        --if objn = tgtobjid and substrb(rawtohex(dhead), 1, 2) = '06' then 400        if objn = tgtobjid then 401          if addpos <= hsz then 402            --utl_file.put_raw(bfw, utl_raw.concat(utl_raw.substr(dhead, 1, addpos-1), addinfo, utl_raw.substr(dhead, addpos+utl_raw.length(addinfo)))); 403            nbody := utl_raw.concat(nbody, 404                                    utl_raw.substr(dhead, 1, addpos - 1), 405                                    addinfo, 406                                    utl_raw.substr(dhead, 407                                                   addpos + 408                                                   utl_raw.length(addinfo))); 409          else 410            --utl_file.put_raw(bfw, dhead); 411            nbody := utl_raw.concat(nbody, dhead); 412          end if; 413          --utl_file.put_raw(bfw, utl_raw.concat(utl_raw.substr(dhead, 1, 8), addinfo, utl_raw.substr(dhead, 9+utl_raw.length(addinfo)))); 414          --nbody := utl_raw.concat(nbody, utl_raw.substr(dhead, 1, 8), addinfo, utl_raw.substr(dhead, 9+utl_raw.length(addinfo))); 415          --trace('[replace_objid_in_file] old id in raw: '||rawtohex(objr)); 416          if endianess > 0 then 417            --trace('[replace_objid_in_file] new id in raw: '||utl_raw.reverse(d2r(newobjid, 8))); 418            --utl_file.put_raw(bfw, utl_raw.reverse(d2r(newobjid, 8))); 419            nbody := utl_raw.concat(nbody, 420                                    utl_raw.reverse(d2r(newobjid, 8))); 421          else 422            --trace('[replace_objid_in_file] new id in raw: '||(d2r(newobjid, 8))); 423            --utl_file.put_raw(bfw, d2r(newobjid, 8)); 424            nbody := utl_raw.concat(nbody, d2r(newobjid, 8)); 425          end if; 426          -- skip objid 427          if addpos > hsz + 5 and addinfo is not null then 428            trace('[replace_objid_in_file] old body len: ' || 429                  utl_raw.length(dbody) || ' new = 4 + ' || 430                  utl_raw.length(utl_raw.substr(dbody, 5, addpos - hsz - 5)) || 431                  ' + ' || utl_raw.length(addinfo) || ' + ' || 432                  utl_raw.length(utl_raw.substr(dbody, 433                                                addpos - hsz - 4 + 434                                                utl_raw.length(addinfo), 435                                                blksz - (addpos - 1) - 436                                                utl_raw.length(dtail) - 437                                                utl_raw.length(addinfo))) || 438                  ' + 4'); 439            --utl_file.put_raw(bfw, utl_raw.concat(utl_raw.substr(dbody, 5, addpos-hsz-5), addinfo, utl_raw.substr(dbody, addpos-hsz, blksz-(addpos-1)-utl_raw.length(dtail)-utl_raw.length(addinfo)))); 440            nbody := utl_raw.concat(nbody, 441                                    utl_raw.substr(dbody, 442                                                   5, 443                                                   addpos - hsz - 5), 444                                    addinfo, 445                                    utl_raw.substr(dbody, 446                                                   addpos - hsz - 4 + 447                                                   utl_raw.length(addinfo), 448                                                   blksz - (addpos - 1) - 449                                                   utl_raw.length(dtail) - 450                                                   utl_raw.length(addinfo))); 451            --trace('[replace_objid_in_file] new body len: '||utl_raw.length(nbody)); 452          elsif addpos = hsz + 5 and addinfo is not null then 453            --utl_file.put_raw(bfw, utl_raw.concat(addinfo, utl_raw.substr(dbody, addpos-hsz, blksz-(addpos-1)-utl_raw.length(dtail)-utl_raw.length(addinfo)))); 454            nbody := utl_raw.concat(nbody, 455                                    addinfo, 456                                    utl_raw.substr(dbody, 457                                                   addpos - hsz, 458                                                   blksz - (addpos - 1) - 459                                                   utl_raw.length(dtail) - 460                                                   utl_raw.length(addinfo))); 461          else 462            --utl_file.put_raw(bfw, utl_raw.substr(dbody, 5, blksz-hsz-4-utl_raw.length(dtail))); 463            nbody := utl_raw.concat(nbody, 464                                    utl_raw.substr(dbody, 465                                                   5, 466                                                   blksz - hsz - 4 - 467                                                   utl_raw.length(dtail))); 468          end if; 469          --trace('[replace_objid_in_file] tail in raw: '||dtail||'('||utl_raw.length(dtail)||')'); 470          --utl_file.put_raw(bfw, dtail); 471          nbody := utl_raw.concat(nbody, dtail); 472          trace('[replace_objid_in_file] new body length: ' || 473                utl_raw.length(nbody)); 474        else 475          --utl_file.put_raw(bfw, dhead); 476          --utl_file.put_raw(bfw, dbody); 477          nbody := utl_raw.concat(nbody, dhead, dbody); 478        end if; 479        --if utl_raw.length(nbody) != blksz then 480        --  trace('[replace_objid_in_file] new body length: '||utl_raw.length(nbody)); 481        --end if; 482        utl_file.put_raw(bfw, nbody); 483 484        utl_file.fflush(bfw); 485      exception 486        when no_data_found then 487          exit; 488        when others then 489          trace('[replace_objid_in_file] ' || SQLERRM); 490          trace('[replace_objid_in_file] ' || 491                dbms_utility.format_error_backtrace); 492          exit; 493      end; 494    end loop; 495    utl_file.fclose(bfw); 496    utl_file.fclose(bfr); 497    if not dstisfilesystem then 498      copy_file(p_tmpdir, p_tmpdstfile, dstdir, dstfile); 499      remove_file(p_tmpdir, p_tmpdstfile); 500    end if; 501    trace('[replace_objid_in_file] completed.'); 502  end; 503 504  function get_cols_no_lob(recowner varchar2, rectab varchar2) 505    return varchar2 as 506    cols  varchar2(32767); 507    colno number := 0; 508  begin 509    cols := ''; 510    for col_rec in (select column_name, data_type, nullable 511                      from dba_tab_cols 512                     where owner = recowner 513                       and table_name = rectab) loop 514      if col_rec.data_type NOT LIKE '%LOB' then 515        if colno > 0 then 516          cols := cols || ','; 517        end if; 518        cols  := cols || col_rec.column_name; 519        colno := colno + 1; 520      end if; 521    end loop; 522    return cols; 523  end; 524 525  function restore_table_row_no_lob(recowner varchar2, 526                                    rectab   varchar2, 527                                    rstowner varchar2, 528                                    rsttab   varchar2, 529                                    cols     varchar2, 530                                    rid      rowid) return number as 531    recnum number := 0; 532  begin 533    begin 534      execute immediate 'insert /*+*/ into ' || rstowner || '.' || rsttab || '(' || cols || 535                        ') select ' || cols || ' from ' || recowner || '.' || 536                        rectab || ' where rowid = :rid' 537        using rid; 538      recnum := recnum + SQL%ROWCOUNT; 539    exception 540      when others then 541        trace('[restore_table_row_no_lob] ' || SQLERRM); 542        trace('[restore_table_row_no_lob] ' || 543              dbms_utility.format_error_backtrace); 544        null; 545    end; 546    return recnum; 547  end; 548 549  function restore_table_in_rows(recowner varchar2, 550                                 rectab   varchar2, 551                                 rstowner varchar2, 552                                 rsttab   varchar2) return number as 553    recnum  number := 0; 554    blk_cur r_cursor; 555    objid   number; 556    fid     number; 557    blkno   number; 558    rnum    number; 559    gnum    number; 560    cols    varchar2(32767); 561  begin 562    begin 563      --trace('[restore_table_in_rows] '||'select dbms_rowid.rowid_object(rowid) objid, dbms_rowid.rowid_relative_fno(rowid) fid, dbms_rowid.rowid_block_number(rowid) blkno, count(1) rnum from '||recowner||'.'||rectab||' group by dbms_rowid.rowid_object(rowid), dbms_rowid.rowid_relative_fno(rowid), dbms_rowid.rowid_block_number(rowid)'); 564      open blk_cur for 'select dbms_rowid.rowid_object(rowid) objid, dbms_rowid.rowid_relative_fno(rowid) fid, dbms_rowid.rowid_block_number(rowid) blkno, count(1) rnum from ' || recowner || '.' || rectab || ' group by dbms_rowid.rowid_object(rowid), dbms_rowid.rowid_relative_fno(rowid), dbms_rowid.rowid_block_number(rowid)'; 565      loop 566        fetch blk_cur 567          into objid, fid, blkno, rnum; 568        exit when blk_cur%NOTFOUND; 569        trace('[restore_table_in_rows] expected rows: ' || rnum); 570        gnum := 0; 571        --trace('[restore_table_in_rows] block: '||blkno); 572        for i in 1 .. rnum loop 573          begin 574            --trace('[restore_table_in_rows] row: '||i); 575            --execute immediate 'insert /*+*/into '||rstowner||'.'||rsttab||' select * from '||recowner||'.'||rectab||' where rowid = dbms_rowid.rowid_create(1, :objid, :fid, :blkno, :i)' using objid, fid, blkno, i-1; 576            execute immediate 'insert /*+*/into ' || rstowner || '.' || 577                              rsttab || ' select * from ' || recowner || '.' || 578                              rectab || 579                              ' where dbms_rowid.rowid_relative_fno(ROWID)=:fid and dbms_rowid.rowid_block_number(ROWID)=:blkno and dbms_rowid.rowid_row_number(ROWID)=:i' 580              using fid, blkno, i - 1; 581            recnum := recnum + SQL%ROWCOUNT; 582            gnum   := gnum + SQL%ROWCOUNT; 583          exception 584            when others then 585              if sqlcode = -22922 then 586                -- trace('[restore_table_in_rows] Warning: Unrecoverable Lob found!'); 587                if cols is null then 588                  cols := get_cols_no_lob(recowner, rectab); 589                end if; 590                recnum := recnum + 591                          restore_table_row_no_lob(recowner, 592                                                   rectab, 593                                                   rstowner, 594                                                   rsttab, 595                                                   cols, 596                                                   dbms_rowid.rowid_create(1, 597                                                                           objid, 598                                                                           fid, 599                                                                           blkno, 600                                                                           i - 1)); 601              else 602                trace('[restore_table_in_rows] ' || SQLERRM); 603                trace('[restore_table_in_rows] ' || 604                      dbms_utility.format_error_backtrace); 605              end if; 606              null; 607          end; 608        end loop; 609        if gnum != rnum then 610          log('Warning: ' || (rnum - gnum) || ' records lost!'); 611        end if; 612      end loop; 613    exception 614      when others then 615        trace('[restore_table_in_rows] ' || sqlerrm); 616        trace('[restore_table_in_rows] ' || 617              dbms_utility.format_error_backtrace); 618        null; 619    end; 620    return recnum; 621  end; 622 623  function restore_table_in_rows_remote(recowner varchar2, 624                                        rectab   varchar2, 625                                        rstowner varchar2, 626                                        rsttab   varchar2, 627                                        dblink   varchar2) return number as 628    recnum  number := 0; 629    blk_cur r_cursor; 630    objid   number; 631    fid     number; 632    blkno   number; 633    rnum    number; 634    cols    varchar2(32767); 635  begin 636    begin 637      --rollback; 638      open blk_cur for 'select dbms_rowid.rowid_object(rowid) objid, dbms_rowid.rowid_relative_fno(rowid) fid, dbms_rowid.rowid_block_number(rowid) blkno, count(1) rnum from ' || recowner || '.' || rectab || ' group by dbms_rowid.rowid_object(rowid), dbms_rowid.rowid_relative_fno(rowid), dbms_rowid.rowid_block_number(rowid)'; 639      loop 640        fetch blk_cur 641          into objid, fid, blkno, rnum; 642        exit when blk_cur%NOTFOUND; 643        trace('[restore_table_in_rows_remote] expected rows: ' || rnum); 644        for i in 1 .. rnum loop 645          begin 646            --execute immediate 'insert /*+no_append*/into '||rstowner||'.'||rsttab||' select * from '||recowner||'.'||rectab||'@'||dblink||' where rowid = dbms_rowid.rowid_create(1, :objid, :fid, :blkno, :i)' using objid, fid, blkno, i-1; 647            execute immediate 'insert /*+*/into ' || rstowner || '.' || 648                              rsttab || ' select * from ' || recowner || '.' || 649                              rectab || '@' || dblink || 650                              ' where dbms_rowid.rowid_relative_fno(ROWID)=:fid and dbms_rowid.rowid_block_number(ROWID)=:blkno and dbms_rowid.rowid_row_number(ROWID)=:i' 651              using fid, blkno, i - 1; 652            recnum := recnum + SQL%ROWCOUNT; 653            --commit; 654          exception 655            when others then 656              if sqlcode = -22922 then 657                if cols is null then 658                  cols := get_cols_no_lob(recowner, rectab); 659                end if; 660                recnum := recnum + 661                          restore_table_row_no_lob(recowner, 662                                                   rectab, 663                                                   rstowner, 664                                                   rsttab, 665                                                   cols, 666                                                   dbms_rowid.rowid_create(1, 667                                                                           objid, 668                                                                           fid, 669                                                                           blkno, 670                                                                           i - 1)); 671              else 672                trace('[restore_table_in_rows_remote] ' || SQLERRM); 673                trace('[restore_table_in_rows_remote] ' || 674                      dbms_utility.format_error_backtrace); 675                --commit; 676              end if; 677              null; 678          end; 679        end loop; 680      end loop; 681    end; 682    return recnum; 683  end; 684 685  function restore_table_ctas(recowner varchar2, 686                              rectab   varchar2, 687                              rstowner varchar2, 688                              rsttab   varchar2) return number as 689    recnum number := 0; 690    tmptab varchar2(30); 691  begin 692    tmptab := gen_table_name(rsttab, '', rstowner); 693    begin 694      execute immediate 'create table ' || rstowner || '.' || tmptab || 695                        ' as select /*+full(t)*/* from ' || recowner || '.' || 696                        rectab || ' t'; 697      execute immediate 'insert /*+append*/ into ' || rstowner || '.' || 698                        rsttab || ' select /*+full(t)*/* from ' || recowner || '.' || 699                        tmptab || ' t'; 700      recnum := SQL%ROWCOUNT; 701      execute immediate 'drop table ' || rstowner || '.' || tmptab; 702    exception 703      when others then 704        --trace('[restore_table_ctas] '||SQLERRM); 705        --trace('[restore_table_ctas] '||dbms_utility.format_error_backtrace); 706        null; 707    end; 708    return recnum; 709  end; 710 711  function restore_table_no_lob(recowner varchar2, 712                                rectab   varchar2, 713                                rstowner varchar2, 714                                rsttab   varchar2) return number as 715    recnum number := 0; 716    cols   varchar2(32767); 717  begin 718    cols := get_cols_no_lob(recowner, rectab); 719 720    begin 721      --execute immediate 'alter system flush buffer_cache'; 722      execute immediate 'insert /*+append*/ into ' || rstowner || '.' || 723                        rsttab || '(' || cols || ') select /*+full(t)*/' || cols || 724                        ' from ' || recowner || '.' || rectab || ' t'; 725 726      recnum := recnum + SQL%ROWCOUNT; 727    exception 728      when others then 729        --raise; 730        if sqlcode = -22922 then 731          null; 732        else 733          recnum := recnum + restore_table_in_rows(recowner, 734                                                   rectab, 735                                                   rstowner, 736                                                   rsttab); 737        end if; 738    end; 739    trace('[restore_table_no_lob] ' || recnum || ' records recovered'); 740    return recnum; 741  end; 742 743  function restore_table(recowner varchar2, 744                         rectab   varchar2, 745                         rstowner varchar2, 746                         rsttab   varchar2, 747                         selflink varchar2 default '') return number as 748    recnum number := 0; 749    expnum number := 0; 750  begin 751    begin 752      trace('[restore_table] Trying to restore data to ' || rstowner || '.' || 753            rsttab); 754      execute immediate 'alter system flush buffer_cache'; 755      if s_tracing then 756        execute immediate 'select /*+full(t)*/count(*) from ' || recowner || '.' || 757                          rectab || ' t' 758          into expnum; 759        trace('[restore_table] Expected Records in this round: ' || expnum); 760      end if; 761      execute immediate 'insert /*+append*/ into ' || rstowner || '.' || 762                        rsttab || ' select /*+full(t)*/* from ' || recowner || '.' || 763                        rectab || ' t'; 764 765      recnum := recnum + SQL%ROWCOUNT; 766      if s_tracing and expnum != SQL%ROWCOUNT then 767        trace('[restore_table] ' || (expnum - SQL%ROWCOUNT) || 768              ' records lost!'); 769        return - 1; -- for test 770      end if; 771    exception 772      when others then 773        --raise; 774        if sqlcode = -22922 then 775          log('Warning: Unrecoverable Lob found!'); 776          recnum := recnum + 777                    restore_table_in_rows_remote(recowner, 778                                                 rectab, 779                                                 rstowner, 780                                                 rsttab, 781                                                 selflink); 782          --recnum := recnum + restore_table_no_lob(recowner, rectab, rstowner, rsttab); 783        else 784          trace(SQLERRM); 785          trace('[restore_table] ' || dbms_utility.format_error_backtrace); 786          --recnum := recnum + restore_table_in_rows_remote(recowner, rectab, rstowner, rsttab, selflink); 787          --return -1; -- test 788          recnum := recnum + restore_table_in_rows(recowner, 789                                                   rectab, 790                                                   rstowner, 791                                                   rsttab); 792        end if; 793    end; 794    execute immediate 'alter system flush buffer_cache'; 795    trace('[restore_table] ' || recnum || ' records recovered'); 796    return recnum; 797  end; 798 799  procedure get_seg_meta(segowner varchar2, 800                         segname  varchar2, 801                         tmpdir   varchar2, 802                         dtail    out raw, 803                         addinfo  out raw, 804                         blksz    number default 8192) as 805    frw      raw(32767); 806    firstblk number; 807    slash    char(1); 808    hdfile   varchar2(255); 809    hdfpath  varchar2(4000); 810    hdfdir   varchar2(255) := 'TMP_HF_DIR'; 811    finaldir varchar2(255); 812    bfo      utl_file.file_type; 813    i        number := 0; 814  begin 815    select decode(instr(platform_name, 'Windows'), 0'/''\') 816      into slash 817      from v_$database 818     where rownum <= 1; 819    select header_block + 1 820      into firstblk 821      from dba_segments 822     where owner = segowner 823       and segment_name = segname; 824    select substr(file_name, instr(d.file_name, slash, -1) + 1), 825           substr(file_name, 1, instr(d.file_name, slash, -1)) 826      into hdfile, hdfpath 827      from dba_data_files d, dba_segments s 828     where s.header_file = d.file_id 829       and s.owner = segowner 830       and s.segment_name = segname; --' 831 832    trace('[get_seg_meta] ' || hdfpath || hdfile); 833    create_directory(hdfpath, hdfdir); 834    -- copy ASM file to temp os folder 835    if hdfpath like '+%' or hdfpath like '/dev/%' then 836      copy_file(hdfdir, hdfile, tmpdir, hdfile); 837      finaldir := tmpdir; 838    else 839      finaldir := hdfdir; 840    end if; 841 842    bfo := utl_file.fopen(finaldir, hdfile, 'RB'); 843 844    -- reach to the truncated data blocks 845    i := 0; 846    while true loop 847      begin 848        utl_file.get_raw(bfo, frw, blksz); 849        i := i + 1; 850 851        exit when i = firstblk; 852      exception 853        when others then 854          exit; 855      end; 856    end loop; 857 858    utl_file.get_raw(bfo, frw, blksz); 859 860    dtail   := utl_raw.substr(frw, blksz - 3, 4); 861    addinfo := utl_raw.substr(frw, 39, 2); 862 863    utl_file.fclose(bfo); 864 865    if hdfpath like '+%' or hdfpath like '/dev/%' then 866      remove_file(tmpdir, hdfile); 867    end if; 868    -- execute immediate 'drop directory '||hdfdir; 869  end; 870 871  function get_seg_data_id(segowner  varchar2, 872                           segname   varchar2, 873                           tmpdir    varchar2, 874                           blksz     number default 8192, 875                           endianess number default 1) return number as 876    frw      raw(32767); 877    hsz      number := 28; 878    firstblk number; 879    slash    char(1); 880    hdfile   varchar2(255); 881    hdfpath  varchar2(4000); 882    hdfdir   varchar2(255) := 'TMP_HF_DIR'; 883    finaldir varchar2(255); 884    bfo      utl_file.file_type; 885    i        number := 0; 886    objr     raw(4); 887    objn     number; 888  begin 889    select decode(instr(platform_name, 'Windows'), 0'/''\') 890      into slash 891      from v_$database 892     where rownum <= 1; 893    select header_block + 1 894      into firstblk 895      from dba_segments 896     where owner = segowner 897       and segment_name = segname; 898    select substr(file_name, instr(d.file_name, slash, -1) + 1), 899           substr(file_name, 1, instr(d.file_name, slash, -1)) 900      into hdfile, hdfpath 901      from dba_data_files d, dba_segments s 902     where s.header_file = d.file_id 903       and s.owner = segowner 904       and s.segment_name = segname; --' 905 906    trace('[get_seg_data_id] ' || hdfpath || hdfile); 907    create_directory(hdfpath, hdfdir); 908    -- copy ASM file to temp os folder 909    if hdfpath like '+%' or hdfpath like '/dev/%' then 910      copy_file(hdfdir, hdfile, tmpdir, hdfile); 911      finaldir := tmpdir; 912    else 913      finaldir := hdfdir; 914    end if; 915 916    bfo := utl_file.fopen(finaldir, hdfile, 'RB'); 917 918    -- reach to the truncated data blocks 919    i := 0; 920    while true loop 921      begin 922        utl_file.get_raw(bfo, frw, blksz); 923        i := i + 1; 924 925        exit when i = firstblk; 926      exception 927        when others then 928          exit; 929      end; 930    end loop; 931 932    utl_file.get_raw(bfo, frw, hsz); 933 934    objr := utl_raw.substr(frw, 25, 4); 935    if endianess > 0 then 936      objn := to_number(rawtohex(utl_raw.reverse(objr)), 'XXXXXXXX'); 937    else 938      objn := to_number(rawtohex(objr), 'XXXXXXXX'); 939    end if; 940 941    utl_file.fclose(bfo); 942 943    if hdfpath like '+%' or hdfpath like '/dev/%' then 944      remove_file(tmpdir, hdfile); 945    end if; 946    -- execute immediate 'drop directory '||hdfdir; 947    return objn; 948  end; 949 950  /************************************************************************ 951  ** Recover Table Data From Special Data File; 952  ** 953  ** oriobjid: Object Id of Table to be Recovered; 954  ** recowner: Owner of Table to be used as recovering dummy table; 955  ** rectable: Name of Table to be used as recovering dummy table; 956  ** rstowner: Owner of Table to store the recovered data; 957  ** rsttable: Name of Table to store the recovered data; 958  ** srcdir: Directory of the Data File to be recovered; 959  ** srcfile: Name of the Data File to be recovered; 960  ** srcisfilesystem: Is the source file located in file system or not; 961  ** tmpdir: Temp Directory to create restore tablespace and other temp files; 962  ** recfile: Name of Data File that rectable is stored; 963  ** coryfile: Name of Copy of Data File that rectable is stored; 964  ** blksz: Block size of the Tablespace Storing the Table to be recovered; 965  ** selflink: database link refer to instance self connect to dba account; 966  ************************************************************************/ 967  procedure recover_table(oriobjid        number, 968                          recowner        varchar2, 969                          rectab          varchar2, 970                          rstowner        varchar2, 971                          rsttab          varchar2, 972                          srcdir          varchar2, 973                          srcfile         varchar2, 974                          srcisfilesystem boolean, 975                          tmpdir          varchar2, 976                          recfile         varchar2, 977                          copyfile        varchar2, 978                          blksz           number default 8192, 979                          fillblks        number default 5, 980                          selflink        varchar2 default '', 981                          endianess       number default 1, 982                          recnum          in out number, 983                          truncblks       in out number) as 984    p_tmpsrcfile  varchar2(30); 985    p_finalsrcdir varchar2(255); 986    -- blk    blob; 987    --vrw    raw(32767); 988    frw   raw(32767); 989    tsz   number := 4; 990    hsz   number := 28; 991    objr  raw(4); 992    objn  number; 993    dtail raw(4); 994    dhead raw(32); 995    dbody raw(32767); 996    --bfr    bfile; 997    bfo         utl_file.file_type; 998    bfr         utl_file.file_type; 999    bfw         utl_file.file_type;1000    fillednum   number := 0;1001    dummyheader number;1002    dummyblks   number;1003    blkstofill  number := fillblks;1004    i           number := 0;1005    j           number := 0;1006    rstnum      number := 0;1007  begin1008    select header_block + 1, blocks - 31009      into dummyheader, dummyblks1010      from dba_segments1011     where owner = recowner1012       and segment_name = rectab;1013    if blkstofill > dummyblks then1014      blkstofill := dummyblks;1015    end if;10161017    if not srcisfilesystem then1018      p_tmpsrcfile := gen_file_name(srcfile, '');1019      copy_file(srcdir, srcfile, tmpdir, p_tmpsrcfile);1020      p_finalsrcdir := tmpdir;1021    else1022      p_tmpsrcfile  := srcfile;1023      p_finalsrcdir := srcdir;1024    end if;10251026    bfo := utl_file.fopen(p_finalsrcdir, p_tmpsrcfile, 'RB');1027    --utl_file.get_raw(bfo, dbody, blksz-hsz-tsz);1028    --utl_file.get_raw(bfo, dtail, tsz);10291030    bfr := utl_file.fopen(tmpdir, copyfile, 'RB');1031    bfw := utl_file.fopen(tmpdir, recfile, 'WB');1032    -- reach to the transaction blocks to be filled1033    i := 0;1034    while true loop1035      begin1036        utl_file.get_raw(bfr, frw, blksz);1037        utl_file.put_raw(bfw, frw);1038        i := i + 1;10391040        exit when i = dummyheader + fillednum;1041      exception1042        when others then1043          --raise;1044          --trace('[recover_table] block NO.: '||i);1045          exit;1046      end;1047    end loop;10481049    -- go through the data file of truncated table1050    while true loop1051      begin1052        --trace('[recover_table] '||j);1053        j := j + 1;1054        --objr := substrb(rawtohex(dhead), 49, 8);1055        utl_file.get_raw(bfo, dhead, hsz);1056        if hsz <= 24 then1057          utl_file.get_raw(bfo, dbody, blksz - tsz - hsz);1058          --objr := substrb(rawtohex(dbody), 49-hsz*2, 8);1059          objr := utl_raw.substr(dbody, 25 - hsz, 4);1060        else1061          --objr := substrb(rawtohex(dhead), 49, 8);1062          objr := utl_raw.substr(dhead, 25, 4);1063        end if;1064        if endianess > 0 then1065          --objn := to_number(utl_raw.reverse(hextoraw(objr)), 'XXXXXXXX');1066          objn := to_number(rawtohex(utl_raw.reverse(objr)), 'XXXXXXXX');1067        else1068          --objn := to_number(hextoraw(objr), 'XXXXXXXX');1069          objn := to_number(rawtohex(objr), 'XXXXXXXX');1070        end if;10711072        -- check if block belongs to truncated table1073        if objn != oriobjid or substrb(rawtohex(dhead), 1, 2) != '06' then1074          if hsz > 24 then1075            utl_file.get_raw(bfo, dbody, blksz - hsz);1076          else1077            utl_file.get_raw(bfo, dtail, tsz);1078          end if;1079        else1080          --trace('[recover_table] Find it.');1081          truncblks := truncblks + 1;1082          if hsz > 24 then1083            utl_file.get_raw(bfo, dbody, blksz - hsz - tsz);1084          end if;1085          utl_file.get_raw(bfo, dtail, tsz);10861087          if not utl_file.is_open(bfr) then1088            bfr := utl_file.fopen(tmpdir, copyfile, 'RB');1089          end if;1090          if not utl_file.is_open(bfw) then1091            bfw := utl_file.fopen(tmpdir, recfile, 'WB');1092          end if;10931094          -- filling the trans block1095          utl_file.get_raw(bfr, dhead, hsz);1096          utl_file.put_raw(bfw, dhead); -- put original header1097          utl_file.put_raw(bfw, dbody); -- replace body1098          utl_file.get_raw(bfr, dbody, blksz - hsz - tsz); -- forward pointer in original file copy1099          utl_file.get_raw(bfr, dtail, tsz); -- get original tail1100          utl_file.put_raw(bfw, dtail); -- put original tail1101          fillednum := fillednum + 1;1102          i         := i + 1;1103          -- no trans data block left, copy recovered data to backup table and fill the left blocks1104          if fillednum >= blkstofill then1105            --if fillednum+blkstofill-1 >= dummyblks then1106            begin1107              while true loop1108                begin1109                  utl_file.get_raw(bfr, frw, blksz);1110                  utl_file.put_raw(bfw, frw);1111                  i := i + 1;11121113                exception1114                  when others then1115                    if utl_file.is_open(bfr) then1116                      utl_file.fclose(bfr);1117                    end if;1118                    if utl_file.is_open(bfw) then1119                      utl_file.fclose(bfw);1120                    end if;1121                    exit;1122                end;1123              end loop;11241125              rstnum := restore_table(recowner,1126                                      rectab,1127                                      rstowner,1128                                      rsttab,1129                                      selflink);1130              -- for test1131              exit when rstnum < 0;1132              recnum    := recnum + rstnum;1133              fillednum := 0;1134              commit;11351136              bfr := utl_file.fopen(tmpdir, copyfile, 'RB');1137              bfw := utl_file.fopen(tmpdir, recfile, 'WB');1138              -- go to the transaction blocks again1139              i := 0;1140              while true loop1141                begin1142                  utl_file.get_raw(bfr, frw, blksz);1143                  utl_file.put_raw(bfw, frw);1144                  i := i + 1;11451146                  exit when i = dummyheader + fillednum;1147                exception1148                  when others then1149                    --raise;1150                    --trace('[recover_table] block NO.: '||i);1151                    exit;1152                end;1153              end loop;1154              utl_file.fflush(bfw);1155            exception1156              when others then1157                trace('[recover_table 2-1] ' || sqlerrm);1158                trace('[recover_table 2-1] ' ||1159                      dbms_utility.format_error_backtrace);1160                null;1161            end;1162          end if;1163        end if;1164      exception1165        when no_data_found then1166          exit;1167        when others then1168          trace('[recover_table 2-2] ' || sqlerrm);1169          trace('[recover_table 2-2] ' ||1170                dbms_utility.format_error_backtrace);1171          exit;1172      end;1173    end loop;11741175    -- last blocks not full filled dummy table1176    --if fillednum+blkstofill-1 < dummyblks then1177    if fillednum < blkstofill and rstnum >= 0 then1178      begin1179        while true loop1180          begin1181            utl_file.get_raw(bfr, frw, blksz);1182            utl_file.put_raw(bfw, frw);1183            i := i + 1;11841185          exception1186            when others then1187              if utl_file.is_open(bfr) then1188                utl_file.fclose(bfr);1189              end if;1190              if utl_file.is_open(bfw) then1191                utl_file.fclose(bfw);1192              end if;1193              exit;1194          end;1195        end loop;1196        recnum := recnum + restore_table(recowner,1197                                         rectab,1198                                         rstowner,1199                                         rsttab,1200                                         selflink);1201        --fillednum := 0;1202        commit;1203      end;1204    end if;1205    if utl_file.is_open(bfr) then1206      utl_file.fclose(bfr);1207    end if;1208    if utl_file.is_open(bfw) then1209      utl_file.fclose(bfw);1210    end if;1211    if utl_file.is_open(bfo) then1212      utl_file.fclose(bfo);1213    end if;1214    utl_file.fclose_all();12151216    log(truncblks || ' truncated data blocks found. ');1217    log(recnum || ' records recovered in backup table ' || rstowner || '.' ||1218        rsttab);12191220    if not srcisfilesystem then1221      remove_file(tmpdir, p_tmpsrcfile);1222    end if;1223  end;12241225  /************************************************************************1226  ** Recover Table Data From Data Files of Targe Table;1227  **1228  ** tgtowner: Owner of Target Table to be recovered;1229  ** tgttable: Name of Target Table to be recovered;1230  ** recowner: Owner of Table to be used as recovering dummy table;1231  ** rectable: Name of Table to be used as recovering dummy table;1232  ** rstowner: Owner of Table to store the recovered data;1233  ** rsttable: Name of Table to store the recovered data;1234  ** tmpdir: Temp Directory to create restore tablespace and other temp files;1235  ** srcfile: Name of the Data File to be recovered;1236  ** recfile: Name of Data File that rectable is stored;1237  ** copydir: Directory of Copy of Data File that rectable is stored;1238  ** coryfile: Name of Copy of Data File that rectable is stored;1239  ** blksz: Block size of the Tablespace Storing the Table to be recovered;1240  ** selflink: database link refer to instance self connect to dba account;1241  ************************************************************************/1242  procedure recover_table(tgtowner      varchar2,1243                          tgttable      varchar2,1244                          recowner      varchar2,1245                          rectab        varchar2,1246                          rstowner      varchar2,1247                          rsttab        varchar2,1248                          tmpdir        varchar2,1249                          recfile       varchar2,1250                          copyfile      varchar2,1251                          blksz         number default 8192,1252                          fillblks      number default 5,1253                          selflink      varchar2 default '',1254                          offline_files varchar2 default null) as1255    tgtobjid   number;1256    recobjid   number;1257    endianess  number;1258    slash      char(1);1259    filedir    varchar2(255) := 'TMP_DATA_FILE_DIR';1260    tmpcopyf   varchar2(256);1261    tsname     varchar2(30);1262    readprop   varchar2(30);1263    dtail      raw(4);1264    addinfo    raw(32);1265    recnum     number := 0;1266    truncblks  number := 0;1267    trecnum    number := 0;1268    ttruncblks number := 0;1269  begin1270    execute immediate 'truncate table ' || rstowner || '.' || rsttab;1271    execute immediate 'alter system set db_block_checking=false scope=memory';1272    execute immediate 'alter system set db_block_checksum=false scope=memory';1273    execute immediate 'alter system set "_db_block_check_objtyp"=false scope=memory';1274    execute immediate 'alter session set events ''10231 trace name context forever, level 10''';1275    execute immediate 'alter session set events ''10233 trace name context forever, level 10''';12761277    select instr(platform_name, 'Windows'),1278           decode(instr(platform_name, 'Windows'), 0, '/', '\')1279      into endianess, slash1280      from v_$database1281     where rownum <= 1;1282    select data_object_id1283      into recobjid1284      from dba_objects1285     where owner = recowner1286       and object_name = rectab1287       and object_type = 'TABLE'1288       and rownum <= 1;1289    log('begin to recover table ' || tgtowner || '.' || tgttable);1290    tgtobjid := get_seg_data_id(tgtowner,1291                                tgttable,1292                                tmpdir,1293                                blksz,1294                                endianess);12951296    if offline_files is not null then1297      for file_rec in (with target_string as1298                          (select /*+inline*/1299                           offline_files str, ';' spliter1300                            from dual),1301                         files as1302                          (select trim(regexp_substr(str,1303                                                    '[^' || spliter || ']+',1304                                                    1,1305                                                    level)) file_name1306                            from target_string1307                          connect by level <=1308                                     length(regexp_replace(str,1309                                                           '[^' || spliter || ']+')) + 1)1310                         select substr(file_name,1311                                       instr(file_name, slash, -1) + 1as filename,1312                                substr(file_name,1313                                       1,1314                                       instr(file_name, slash, -1)) as filepath1315                           from files1316                          where file_name is not nullloop1317        --'1318        begin1319          log('Recovering data in datafile ' || file_rec.filepath ||1320              file_rec.filename);1321          recnum    := 0;1322          truncblks := 0;1323          create_directory(file_rec.filepath, filedir);1324          recover_table(tgtobjid,1325                        recowner,1326                        rectab,1327                        rstowner,1328                        rsttab,1329                        filedir,1330                        file_rec.filename,1331                        (file_rec.filepath not like '+%' and1332                        file_rec.filepath not like '/dev/%'),1333                        tmpdir,1334                        recfile,1335                        copyfile,1336                        blksz,1337                        fillblks,1338                        selflink,1339                        endianess,1340                        recnum,1341                        truncblks);1342          -- execute immediate 'drop directory '||filedir;1343          trecnum    := trecnum + recnum;1344          ttruncblks := ttruncblks + truncblks;1345        exception1346          when others then1347            trace('[recover_table 1] ' || sqlerrm);1348            trace('[recover_table 1] ' ||1349                  dbms_utility.format_error_backtrace);1350        end;1351      end loop;1352    else1353      if s_repobjid then1354        get_seg_meta(recowner, rectab, tmpdir, dtail, addinfo, blksz);1355        select tablespace_name1356          into tsname1357          from dba_tables1358         where owner = tgtowner1359           and table_name = tgttable1360           and rownum <= 1;1361        select STATUS1362          into readprop1363          from dba_tablespaces1364         where tablespace_name = tsname;1365        if readprop != 'READ ONLY' then1366          execute immediate 'alter tablespace ' || tsname || ' read only';1367          execute immediate 'alter system flush buffer_cache';1368        end if;1369        --for file_rec in (select substr(file_name,decode(instr(d.file_name, '\', -1), 0, instr(file_name, '/', -1), instr(file_name, '\', -1))+1) as filename,1370        --                        substr(file_name,1,decode(instr(d.file_name, '\', -1), 0, instr(file_name, '/', -1), instr(file_name, '\', -1))) as filepath1371        --                   from dba_data_files d, dba_tables t1372        --                   where d.tablespace_name = t.tablespace_name and t.owner = tgtowner and t.table_name = tgttable) loop --'1373        for file_rec in (select substr(file_name,1374                                       instr(d.file_name, slash, -1) + 1as filename,1375                                substr(file_name,1376                                       1,1377                                       instr(d.file_name, slash, -1)) as filepath1378                           from dba_data_files d, dba_tables t1379                          where d.tablespace_name = t.tablespace_name1380                            and t.owner = tgtowner1381                            and t.table_name = tgttable) loop1382          --'1383          begin1384            log('Recovering data in datafile ' || file_rec.filepath ||1385                file_rec.filename);1386            recnum    := 0;1387            truncblks := 0;1388            create_directory(file_rec.filepath, filedir);1389            tmpcopyf := gen_file_name(file_rec.filename, '');1390            copy_file(filedir, file_rec.filename, tmpdir, tmpcopyf);1391            --replace_segmeta_in_file(srcdir, tmpcopyf, srcdir, file_rec.filename, tgtobjid, recobjid, dtail, 39, addinfo, blksz, endianess);1392            replace_segmeta_in_file(tmpdir,1393                                    tmpcopyf,1394                                    filedir,1395                                    file_rec.filename,1396                                    (file_rec.filepath not like '+%' and1397                                    file_rec.filepath not like '/dev/%'),1398                                    tgtobjid,1399                                    recobjid,1400                                    dtail,1401                                    39,1402                                    '',1403                                    blksz,1404                                    endianess);1405            recover_table(recobjid,1406                          recowner,1407                          rectab,1408                          rstowner,1409                          rsttab,1410                          filedir,1411                          file_rec.filename,1412                          (file_rec.filepath not like '+%' and1413                          file_rec.filepath not like '/dev/%'),1414                          tmpdir,1415                          recfile,1416                          copyfile,1417                          blksz,1418                          fillblks,1419                          selflink,1420                          endianess,1421                          recnum,1422                          truncblks);1423            --recover_table(tgtobjid, recowner, rectab, rstowner, rsttab, srcdir, file_rec.filename, recdir, recfile, copydir, copyfile, blksz, fillblks, selflink, endianess);1424            copy_file(tmpdir, tmpcopyf, filedir, file_rec.filename);1425            remove_file(tmpdir, tmpcopyf);1426            -- execute immediate 'drop directory '||filedir;1427            trecnum    := trecnum + recnum;1428            ttruncblks := ttruncblks + truncblks;1429            trace('[recover_table 1] ' || tmpcopyf || ' removed.');1430          exception1431            when others then1432              trace('[recover_table 1] ' || sqlerrm);1433              trace('[recover_table 1] ' ||1434                    dbms_utility.format_error_backtrace);1435          end;1436        end loop;1437        if readprop != 'READ ONLY' then1438          execute immediate 'alter tablespace ' || tsname || ' read write';1439        end if;1440      else1441        for file_rec in (select substr(file_name,1442                                       instr(d.file_name, slash, -1) + 1as filename,1443                                substr(file_name,1444                                       1,1445                                       instr(d.file_name, slash, -1)) as filepath1446                           from dba_data_files d, dba_tables t1447                          where d.tablespace_name = t.tablespace_name1448                            and t.owner = tgtowner1449                            and t.table_name = tgttable) loop1450          --'1451          begin1452            log('Recovering data in datafile ' || file_rec.filepath ||1453                file_rec.filename);1454            recnum    := 0;1455            truncblks := 0;1456            create_directory(file_rec.filepath, filedir);1457            recover_table(tgtobjid,1458                          recowner,1459                          rectab,1460                          rstowner,1461                          rsttab,1462                          filedir,1463                          file_rec.filename,1464                          (file_rec.filepath not like '+%' and1465                          file_rec.filepath not like '/dev/%'),1466                          tmpdir,1467                          recfile,1468                          copyfile,1469                          blksz,1470                          fillblks,1471                          selflink,1472                          endianess,1473                          recnum,1474                          truncblks);1475            -- execute immediate 'drop directory '||filedir;1476            trecnum    := trecnum + recnum;1477            ttruncblks := ttruncblks + truncblks;1478          exception1479            when others then1480              trace('[recover_table 1] ' || sqlerrm);1481              trace('[recover_table 1] ' ||1482                    dbms_utility.format_error_backtrace);1483          end;1484        end loop;1485      end if;1486    end if;14871488    log('Total: ' || ttruncblks || ' truncated data blocks found. ');1489    log('Total: ' || trecnum || ' records recovered in backup table ' ||1490        rstowner || '.' || rsttab);14911492    execute immediate 'alter session set events ''10233 trace name context off''';1493    execute immediate 'alter session set events ''10231 trace name context off''';1494    execute immediate 'alter system set "_db_block_check_objtyp"=true scope=memory';1495    execute immediate 'alter system set db_block_checksum=true scope=memory';1496    execute immediate 'alter system set db_block_checking=true scope=memory';14971498    log('Recovery completed.');1499  end;15001501  /************************************************************************1502  ** Prepare the data files to be use during recovering;1503  **1504  ** tgtowner: Owner of Target Table to be recovered;1505  ** tgttable: Name of Target Table to be recovered;1506  ** datapath: Absolute path of Data Files;1507  ** datadir: Directory to be created referring to datapath;1508  ** rects: Tablespace to store the recovering dummy table;1509  ** recfile: Name of Data File to store the recovering dummy table;1510  ** rstts: Tablespace to store table storing the recovered data;1511  ** rstfile: Name of Data File to store restoring table;1512  ** blksz: Block size of the Tablespace Storing the Table to be recovered;1513  ** rectsblks: block number of recovery tablespace1514  ** rectsblks: block number of restore tablespace1515  ************************************************************************/1516  procedure prepare_files(tgtowner  varchar2,1517                          tgttable  varchar2,1518                          tmppath   varchar2,1519                          rects     out varchar2,1520                          recfile   out varchar2,1521                          rstts     out varchar2,1522                          rstfile   out varchar2,1523                          blksz     out varchar2,1524                          rectsblks number default 16,1525                          rsttsblks number default 2560) as1526    ext_mgmt varchar2(30);1527    ss_mgmt  varchar2(30);1528    slash    char(1);1529  begin1530    select decode(instr(platform_name, 'Windows'), 0, '/', '\')1531      into slash1532      from v_$database1533     where rownum <= 1;15341535    select block_size, extent_management, segment_space_management1536      into blksz, ext_mgmt, ss_mgmt1537      from dba_tablespaces ts, dba_tables t1538     where t.tablespace_name = ts.tablespace_name1539       and t.owner = upper(tgtowner)1540       and t.table_name = upper(tgttable);15411542    --select 'FY_REC_DATA'||surfix into rects from (select surfix from (select null surfix from dual union all select level surfix from dual connect by level <= 255) where not exists (select 1 from dba_tablespaces where tablespace_name = 'FY_REC_DATA'||surfix) order by surfix nulls first) where rownum<=1;1543    --select 'FY_REC_DATA'||surfix||'.DAT' into recfile from (select surfix from (select null surfix from dual union all select level surfix from dual connect by level <= 255) where not exists (select 1 from dba_data_files where file_name like '%\FY_REC_DATA'||surfix||'.DAT') order by surfix nulls first) where rownum<=1;1544    rects   := gen_ts_name('FY_REC_DATA', '');1545    recfile := gen_file_name('FY_REC_DATA', '');1546    log('Recover Tablespace' || rects || '; Data File: ' || recfile);1547    execute immediate 'create tablespace ' || rects || ' datafile ''' ||1548                      rtrim(tmppath, slash) || slash || recfile ||1549                      ''' size ' || to_char(blksz * rectsblks / 1024) ||1550                      'K autoextend off extent management ' || ext_mgmt ||1551                      ' SEGMENT SPACE MANAGEMENT ' || ss_mgmt; --'15521553    --select 'FY_RST_DATA'||surfix into rstts from (select surfix from (select null surfix from dual union all select level surfix from dual connect by level <= 255) where not exists (select 1 from dba_tablespaces where tablespace_name = 'FY_REST_DATA'||surfix) order by surfix nulls first) where rownum<=1;1554    --select 'FY_RST_DATA'||surfix||'.DAT' into rstfile from (select surfix from (select null surfix from dual union all select level surfix from dual connect by level <= 255) where not exists (select 1 from dba_data_files where file_name like '%\FY_REST_DATA'||surfix||'.DAT') order by surfix nulls first) where rownum<=1;1555    rstts   := gen_ts_name('FY_RST_DATA', '');1556    rstfile := gen_file_name('FY_RST_DATA', '');1557    log('Restore Tablespace' || rstts || '; Data File: ' || rstfile);1558    execute immediate 'create tablespace ' || rstts || ' datafile ''' ||1559                      rtrim(tmppath, slash) || slash || rstfile ||1560                      ''' size ' || to_char(blksz * rsttsblks / 1024) ||1561                      'K autoextend on extent management ' || ext_mgmt ||1562                      ' SEGMENT SPACE MANAGEMENT ' || ss_mgmt; --'1563  end;15641565  /************************************************************************1566  ** Clean up existing Recover and Restore Tablespace. Drop tables in the tablespaces1567  **1568  ** rects: Recover tablespace name1569  ** rects: Restore tablespace name, default NULL, will not do cleaning up;1570  ************************************************************************/1571  procedure clean_up_ts(rects varchar2, rstts varchar2 default null) as1572    readprop varchar2(30);1573  begin1574    select STATUS1575      into readprop1576      from dba_tablespaces1577     where tablespace_name = rects;1578    if readprop = 'READ ONLY' then1579      execute immediate 'alter tablespace ' || rects || ' read write';1580    end if;1581    for tab_rec in (select owner, table_name1582                      from dba_tables1583                     where tablespace_name = rects) loop1584      execute immediate 'drop table ' || tab_rec.owner || '.' ||1585                        tab_rec.table_name;1586    end loop;1587    if rstts is not null then1588      for tab_rec in (select owner, table_name1589                        from dba_tables1590                       where tablespace_name = rstts) loop1591        execute immediate 'drop table ' || tab_rec.owner || '.' ||1592                          tab_rec.table_name;1593      end loop;1594    end if;1595  end;15961597  /************************************************************************1598  ** Fill Blocks of Recovering Table, to format the blocks;1599  **1600  ** tgtowner: Owner of Target Table to be recovered;1601  ** tgttable: Name of Target Table to be recovered;1602  ** tmpdir: Temp Directory to be used to create the restore tablespace and files;1603  ** rects: Tablespace to store the recovering dummy table;1604  ** recfile: Name of Data File to store the recovering dummy table;1605  ** rstts: Tablespace to store table storing the recovered data;1606  ** blks: Number blocks in Initial Extent of the recovering dummy table;1607  ** recowner: Owner of Table to be used as recovering dummy table;1608  ** rstowner: Owner of Table to store the recovered data;1609  ** rectable: Name of Table to be used as recovering dummy table;1610  ** rsttable: Name of Table to store the recovered data;1611  ** coryfile: Name of Copy of Data File that rectable is stored;1612  ************************************************************************/1613  procedure fill_blocks(tgtowner varchar2,1614                        tgttable varchar2,1615                        tmpdir   varchar2,1616                        rects    varchar2,1617                        recfile  varchar2,1618                        rstts    varchar2,1619                        blks     number default 8,1620                        recowner varchar2 default user,1621                        rstowner varchar2 default user,1622                        rectab   in out varchar2,1623                        rsttab   in out varchar2,1624                        copyfile out varchar2) as1625    blksz number;1626    blkno number;1627    cols  varchar2(32767);1628    vals  varchar2(32767);1629    colno number := 0;1630  begin1631    if rectab is null then1632      select block_size1633        into blksz1634        from dba_tablespaces ts, dba_tables t1635       where t.tablespace_name = ts.tablespace_name1636         and t.owner = upper(tgtowner)1637         and t.table_name = upper(tgttable);1638      -- select upper(tgttable||'$'||surfix) into rectab from (select surfix from (select null surfix from dual union all select level surfix from dual connect by level <= 255) where not exists (select 1 from dba_tables where owner = recowner and table_name = upper(tgttable||'$'||surfix)) order by surfix nulls first) where rownum<=1;1639      rectab := gen_table_name(tgttable, '$', recowner);1640      log('Recover Table: ' || recowner || '.' || rectab);1641      --trace('[fill_blocks] create table '||recowner||'.'||rectab||' tablespace '||rects||' storage(initial '||to_char(blks*blksz/1024)||'K) as select * from '||tgtowner||'.'||tgttable||' where 1=2');1642      execute immediate 'create table ' || recowner || '.' || rectab ||1643                        ' tablespace ' || rects || ' storage(initial ' ||1644                        to_char(blks * blksz / 1024) ||1645                        'K) as select * from ' || tgtowner || '.' ||1646                        tgttable || ' where 1=2';1647    else1648      --execute immediate 'truncate table '||recowner||'.'||rectab;1649      execute immediate 'delete from ' || recowner || '.' || rectab;1650      commit;1651    end if;16521653    cols := '';1654    vals := '';1655    for col_rec in (select column_name, data_type, nullable1656                      from dba_tab_cols1657                     where owner = recowner1658                       and table_name = rectab) loop1659      if col_rec.nullable = 'N' then1660        execute immediate 'alter table ' || recowner || '.' || rectab ||1661                          ' modify ' || col_rec.column_name || ' null';1662      end if;1663      if colno < 6 then1664        if col_rec.data_type like '%CHAR%' or1665           col_rec.data_type like '%RAW%' then1666          if colno > 0 then1667            cols := cols || ',';1668            vals := vals || ',';1669          end if;1670          cols  := cols || col_rec.column_name;1671          vals  := vals || '''A''';1672          colno := colno + 1;1673        elsif col_rec.data_type like '%NUMBER%' or1674              col_rec.data_type = 'FLOAT' then1675          if colno > 0 then1676            cols := cols || ',';1677            vals := vals || ',';1678          end if;1679          cols  := cols || col_rec.column_name;1680          vals  := vals || '0';1681          colno := colno + 1;1682        elsif col_rec.data_type LIKE '%TIMESTAMP%' or1683              col_rec.data_type = 'DATE' then1684          if colno > 0 then1685            cols := cols || ',';1686            vals := vals || ',';1687          end if;1688          cols  := cols || col_rec.column_name;1689          vals  := vals || 'sysdate';1690          colno := colno + 1;1691        end if;1692      end if;1693    end loop;16941695    --select upper(tgttable||'$$'||surfix) into rsttab from (select surfix from (select null surfix from dual union all select level surfix from dual connect by level <= 255) where not exists (select 1 from dba_tables where owner = rstowner and table_name = upper(tgttable||'$$'||surfix)) order by surfix nulls first) where rownum<=1;1696    if rsttab is null then1697      rsttab := gen_table_name(tgttable, '$$', rstowner);1698      log('Restore Table' || rstowner || '.' || rsttab);1699      execute immediate 'create table ' || rstowner || '.' || rsttab ||1700                        ' tablespace ' || rstts || ' as select * from ' ||1701                        recowner || '.' || rectab || ' where 1=2';1702    else1703      execute immediate 'truncate table ' || rstowner || '.' || rsttab;1704    end if;17051706    --trace('[fill_blocks] insert into '||recowner||'.'||rectab||'('||cols||'values ('||vals||')');1707    while true loop1708      execute immediate 'insert into ' || recowner || '.' || rectab || '(' || cols ||1709                        'values (' || vals || ')';1710      execute immediate 'select count(unique(dbms_rowid.rowid_block_number( rowid ))) from ' ||1711                        recowner || '.' || rectab1712        into blkno;1713      exit when blkno >= blks - 3;1714    end loop;1715    commit;1716    execute immediate 'alter system flush buffer_cache';1717    execute immediate 'delete from ' || recowner || '.' || rectab;1718    commit;1719    execute immediate 'alter system flush buffer_cache';1720    trace('[fill_blocks] Data Blocks formatted.');17211722    execute immediate 'alter tablespace ' || rects || ' read only';17231724    select 'FY_REC_DATA_COPY' || surfix || '.DAT'1725      into copyfile1726      from (select surfix1727              from (select null surfix1728                      from dual1729                    union all1730                    select level surfix1731                      from dual1732                    connect by level <= 255)1733             where not exists1734             (select 11735                      from dba_data_files1736                     where file_name like1737                           '%FY_REC_DATA_COPY' || surfix || '.DAT')1738             order by surfix nulls first)1739     where rownum <= 1;1740    copy_file(tmpdir, recfile, tmpdir, copyfile);1741    log('Copy file of Recover Tablespace' || copyfile);1742  end;17431744  /************************************************************************1745  ** Create recovery table on new file of truncated table'tablespace;1746  **1747  ** tgtowner: Owner of Target Table to be recovered;1748  ** tgttable: Name of Target Table to be recovered;1749  ** datadir: Directory to be created referring to datapath;1750  ** rects: Tablespace to store the recovering dummy table;1751  ** recfid: ID of Data File to store the recovering dummy table;1752  ** recfile: Name of Data File to store the recovering dummy table;1753  ** rectable: Name of Table to be used as recovering dummy table;1754  ** blks: Number blocks in Initial Extent of the recovering dummy table;1755  ** rectsblks: block number of recovery tablespace1756  ************************************************************************/1757  procedure create_rectab_on_tgttab_ts(tgtowner  varchar2,1758                                       tgttable  varchar2,1759                                       datadir   varchar2,1760                                       recowner  varchar2 default user,1761                                       rects     out varchar2,1762                                       recfid    in out number,1763                                       recfile   out varchar2,1764                                       rectab    out varchar2,1765                                       blks      number default 8,1766                                       rectsblks number default 16) as1767    blksz    number;1768    tsid     number;1769    tsonline number;1770    datapath varchar2(32767);1771    r_files  r_cursor;1772    filelist t_fileprops;1773    tn       number;1774  begin1775    select ts.ts#, ts.name, ts.online$, blocksize1776      into tsid, rects, tsonline, blksz1777      from sys.ts$ ts, dba_tables t1778     where t.tablespace_name = ts.name1779       and t.owner = upper(tgtowner)1780       and t.table_name = upper(tgttable);1781    if tsonline = 4 then1782      execute immediate 'alter tablespace ' || rects || ' read write';1783    end if;17841785    if recfid is null then1786      open r_files for1787        select file#, status$ bulk from sys.file$ where ts# = tsid;1788      fetch r_files bulk collect1789        into filelist;1790      recfile := gen_file_name('FY_REC_DATA', '');1791      select rtrim(directory_path, '\') || '\'1792        into datapath1793        from dba_directories1794       where directory_name = datadir; --'1795      execute immediate 'alter tablespace ' || rects || ' add datafile ''' ||1796                        datapath || recfile || ''' size ' ||1797                        to_char(rectsblks * blksz / 1024) || 'K';1798      select file_id1799        into recfid1800        from dba_data_files1801       where tablespace_name = rects1802         and (file_name like '%\' || recfile or1803             file_name like '%/' || recfile); --'1804    else1805      open r_files for1806        select file#, status$ bulk1807          from sys.file$1808         where ts# = tsid1809           and file# != recfid;1810      fetch r_files bulk collect1811        into filelist;1812      trace('[create_rectab_on_tgttab_ts] file id: ' || recfid);1813      select decode(instr(file_name, '/'-1),1814                    0,1815                    substr(file_name, instr(file_name, '\', -1) + 1),1816                    substr(file_name, instr(file_name, '/', -1) + 1))1817        into recfile1818        from dba_data_files1819       where file_id = recfid; --'1820    end if;1821    log('Recover Tablespace: ' || recfile || '(' || recfid || ')');1822    for i in 1 .. filelist.count loop1823      update sys.file$ f1824         set status$ = 11825       where ts# = tsid1826         and file# = filelist(i).file#;1827    end loop;1828    commit;1829    execute immediate 'alter system flush buffer_cache';1830    --select file# into tn from sys.file$ where ts#=tsid and status$=2;1831    --trace('[create_rectab_on_tgttab_ts] inactive files: '||filelist.count);1832    --trace('[create_rectab_on_tgttab_ts] active file id: '||tn);1833    rectab := gen_table_name(tgttable, '$', recowner);1834    log('Recover Table: ' || recowner || '.' || rectab);1835    --dbms_lock.sleep(3);1836    execute immediate 'create table ' || recowner || '.' || rectab ||1837                      ' tablespace ' || rects || ' storage(initial ' ||1838                      to_char(blks * blksz / 1024) ||1839                      'K) as select * from ' || tgtowner || '.' || tgttable ||1840                      ' where 1=2';1841    select header_file1842      into tn1843      from dba_segments1844     where owner = recowner1845       and segment_name = rectab;1846    trace('[create_rectab_on_tgttab_ts] header file: ' || filelist.count);1847    for i in 1 .. filelist.count loop1848      update sys.file$ f1849         set status$ = filelist(i).status$1850       where ts# = tsid1851         and file# = filelist(i).file#;1852    end loop;1853    commit;1854    execute immediate 'alter system flush buffer_cache';1855  end;18561857  procedure replace_segraw_in_file(srcdir   varchar2,1858                                   srcfile  varchar2,1859                                   dstdir   varchar2,1860                                   dstfile  varchar2,1861                                   blknum   number,1862                                   startpos number,1863                                   repcont  raw,1864                                   blksz    number default 8192) as1865    bfr       utl_file.file_type;1866    bfw       utl_file.file_type;1867    dbody     raw(32767);1868    i         number;1869    p_srcdir  varchar2(255) := srcdir;1870    p_srcfile varchar2(255) := srcfile;1871    p_dstdir  varchar2(255) := dstdir;1872    p_dstfile varchar2(255) := dstfile;1873  begin1874    if p_dstdir is null then1875      p_dstdir := p_srcdir;1876    end if;1877    trace('[replace_segraw_in_file] replace block id' || blknum ||1878          ' start' || startpos || ' content' || repcont);1879    bfr := utl_file.fopen(p_srcdir, p_srcfile, 'RB');1880    bfw := utl_file.fopen(p_dstdir, p_dstfile, 'WB');18811882    i := 0;1883    while true loop1884      begin1885        utl_file.get_raw(bfr, dbody, blksz);1886        utl_file.put_raw(bfw, dbody);1887        i := i + 1;18881889        exit when i = blknum - 1;1890      exception1891        when others then1892          exit;1893      end;1894    end loop;18951896    utl_file.get_raw(bfr, dbody, blksz);1897    if startpos <= 1 then1898      utl_file.put_raw(bfw,1899                       utl_raw.concat(repcont,1900                                      utl_raw.substr(dbody,1901                                                     1 +1902                                                     utl_raw.length(repcont))));1903    else1904      utl_file.put_raw(bfw,1905                       utl_raw.concat(utl_raw.substr(dbody, 1, startpos - 1),1906                                      repcont,1907                                      utl_raw.substr(dbody,1908                                                     startpos +1909                                                     utl_raw.length(repcont))));1910    end if;19111912    while true loop1913      begin1914        utl_file.get_raw(bfr, dbody, blksz);1915        utl_file.put_raw(bfw, dbody);19161917      exception1918        when no_data_found then1919          exit;1920        when others then1921          trace('[replace_segraw_in_file] ' || SQLERRM);1922          trace('[replace_segraw_in_file] ' ||1923                dbms_utility.format_error_backtrace);1924          exit;1925      end;1926    end loop;19271928    utl_file.fclose(bfw);1929    utl_file.fclose(bfr);1930    trace('[replace_segraw_in_file] completed.');1931  end;19321933  procedure dump_seg_block_raw(hdfile varchar2,1934                               srcdir varchar2,1935                               blknb  number,1936                               blksz  number default 8192) as1937    frw raw(32767);1938    bfo utl_file.file_type;1939    bfw utl_file.file_type;1940    i   number := 0;1941  begin1942    bfo := utl_file.fopen(srcdir, hdfile, 'RB');1943    bfw := utl_file.fopen(srcdir, hdfile || '_' || blknb || '.BLK', 'WB');19441945    -- reach to the truncated data blocks1946    i := 0;1947    while true loop1948      begin1949        utl_file.get_raw(bfo, frw, blksz);1950        i := i + 1;19511952        exit when i = blknb;1953      exception1954        when others then1955          exit;1956      end;1957    end loop;19581959    utl_file.get_raw(bfo, frw, blksz);1960    utl_file.put_raw(bfw, frw);19611962    utl_file.fclose(bfo);1963    utl_file.fclose(bfw);1964  end;1965  /*------------------------------------------------------------------------------------------1966    procedure test_chain(filename varchar2,1967                         blknum number,1968                         startpos number,1969                         repcont raw,1970                         srcdir varchar2 default 'FY_DATA_DIR')1971    as1972      tmpcopyf varchar2(256);1973    begin1974      execute immediate 'alter system set db_block_checking=false scope=memory';1975      execute immediate 'alter system set db_block_checksum=false scope=memory';1976      execute immediate 'alter system set "_db_block_check_objtyp"=false scope=memory';1977      execute immediate 'alter session set events ''10231 trace name context forever, level 10''';1978      execute immediate 'alter session set events ''10233 trace name context forever, level 10''';1979      begin1980        tmpcopyf := gen_file_name(filename, '$');1981        trace('[test_chain] bakcup file '||tmpcopyf);1982        copy_file(srcdir, filename, srcdir, tmpcopyf);1983        replace_segraw_in_file(srcdir, tmpcopyf, srcdir, filename, blknum, startpos, repcont, 8192);1984        execute immediate 'alter system flush buffer_cache';1985        for rec in (select * from t_chain where rowid='AABFUoAAHAAAABFAAA') loop1986          null;1987        end loop;1988        trace('[test_chain] table query completed');1989      exception when others then1990        trace('[test_chain] '||sqlerrm);1991        trace('[test_chain] '||dbms_utility.format_error_backtrace);1992      end;1993      copy_file(srcdir, tmpcopyf, srcdir, filename);1994      remove_file(srcdir, tmpcopyf);1995      trace('[test_chain] '||tmpcopyf||' removed.');1996      execute immediate 'alter system set db_block_checking=true scope=memory';1997      execute immediate 'alter system set db_block_checksum=true scope=memory';1998      execute immediate 'alter system set "_db_block_check_objtyp"=true scope=memory';1999      execute immediate 'alter session set events ''10231 trace name context off''';2000      execute immediate 'alter session set events ''10233 trace name context off''';2001    exception when others then2002      trace('[test_chain] '||sqlerrm);2003      trace('[test_chain] '||dbms_utility.format_error_backtrace);2004    end;2005  ------------------------------------------------------------------------------------------*/2006  procedure test_rec1(tow     varchar2 default 'DEMO',2007                      ttb     varchar2 default 'T_CHAIN',2008                      fbks    number default 1,2009                      tmppath varchar2 default '/tmp/') --'2010   as2011    tgtowner varchar2(30) := upper(tow);2012    tgttable varchar2(30) := upper(ttb);2013    tmpdir   varchar2(30);2014    rects    varchar2(30);2015    recfile  varchar2(30);2016    rstts    varchar2(30);2017    rstfile  varchar2(30);2018    blksz    number;2019    rectab   varchar2(30);2020    rsttab   varchar2(30);2021    copyfile varchar2(30);2022  begin2023    tmpdir := 'FY_DATA_DIR';2024    create_directory(tmppath, tmpdir);2025    prepare_files(tgtowner,2026                  tgttable,2027                  tmpdir,2028                  rects,2029                  recfile,2030                  rstts,2031                  rstfile,2032                  blksz);2033    rects   := 'FY_REC_DATA';2034    rstts   := 'FY_RST_DATA';2035    recfile := 'FY_REC_DATA.DAT';2036    fill_blocks(tgtowner,2037                tgttable,2038                tmpdir,2039                rects,2040                recfile,2041                rstts,2042                8,2043                tgtowner,2044                tgtowner,2045                rectab,2046                rsttab,2047                copyfile);2048    recover_table(tgtowner,2049                  tgttable,2050                  tgtowner,2051                  rectab,2052                  tgtowner,2053                  rsttab,2054                  tmpdir,2055                  recfile,2056                  copyfile,2057                  blksz,2058                  fbks,2059                  'myself');2060    -- execute immediate 'drop directory '||tmpdir;2061  end;20622063  procedure test_rec2(tow  varchar2 default 'DEMO',2064                      ttb  varchar2 default 'T_CHAIN',2065                      fbks number default 1) as2066    tgtowner varchar2(30) := upper(tow);2067    tgttable varchar2(30) := upper(ttb);2068    tmpdir   varchar2(30);2069    rects    varchar2(30);2070    recfile  varchar2(30);2071    rstts    varchar2(30);2072    blksz    number;2073    rectab   varchar2(30);2074    rsttab   varchar2(30);2075    copyfile varchar2(30);2076  begin2077    tmpdir  := 'FY_DATA_DIR';2078    rects   := 'FY_REC_DATA';2079    rstts   := 'FY_RST_DATA';2080    recfile := 'FY_REC_DATA.DAT';2081    clean_up_ts(rects, rstts);2082    select block_size2083      into blksz2084      from dba_tablespaces ts, dba_tables t2085     where ts.tablespace_name = t.tablespace_name2086       and t.owner = tgtowner2087       and t.table_name = tgttable;2088    fill_blocks(tgtowner,2089                tgttable,2090                tmpdir,2091                rects,2092                recfile,2093                rstts,2094                8,2095                tgtowner,2096                tgtowner,2097                rectab,2098                rsttab,2099                copyfile);2100    recover_table(tgtowner,2101                  tgttable,2102                  tgtowner,2103                  rectab,2104                  tgtowner,2105                  rsttab,2106                  tmpdir,2107                  recfile,2108                  copyfile,2109                  blksz,2110                  fbks,2111                  'myself');2112    -- execute immediate 'drop directory '||tmpdir;2113  end;21142115  procedure test_rec3(tow  varchar2 default 'DEMO',2116                      ttb  varchar2 default 'T_CHAIN',2117                      fbks number default 1,2118                      fid  number default null) as2119    tgtowner varchar2(30) := upper(tow);2120    tgttable varchar2(30) := upper(ttb);2121    tmpdir   varchar2(30);2122    rects    varchar2(30);2123    recfile  varchar2(30);2124    rstts    varchar2(30);2125    blksz    number;2126    rectab   varchar2(30);2127    rsttab   varchar2(30);2128    copyfile varchar2(30);2129    recfid   number := fid;2130  begin2131    tmpdir := 'FY_DATA_DIR';2132    rstts  := 'FY_RST_DATA';2133    --begin2134    --  execute immediate 'drop table '||tgtowner||'.'||tgttable||'$';2135    --  execute immediate 'drop table '||tgtowner||'.'||tgttable||'$$';2136    --exception when others then2137    --  null;2138    --end;2139    create_rectab_on_tgttab_ts(tgtowner,2140                               tgttable,2141                               tmpdir,2142                               tgtowner,2143                               rects,2144                               recfid,2145                               recfile,2146                               rectab,2147                               8,2148                               16);2149    select block_size2150      into blksz2151      from dba_tablespaces ts, dba_tables t2152     where ts.tablespace_name = t.tablespace_name2153       and t.owner = tgtowner2154       and t.table_name = tgttable;2155    fill_blocks(tgtowner,2156                tgttable,2157                tmpdir,2158                rects,2159                recfile,2160                rstts,2161                8,2162                tgtowner,2163                tgtowner,2164                rectab,2165                rsttab,2166                copyfile);2167    recover_table(tgtowner,2168                  tgttable,2169                  tgtowner,2170                  rectab,2171                  tgtowner,2172                  rsttab,2173                  tmpdir,2174                  recfile,2175                  copyfile,2176                  blksz,2177                  fbks,2178                  'myself');2179    -- execute immediate 'drop directory '||tmpdir;2180    begin2181      --execute immediate 'drop table '||tgtowner||'.'||rectab;2182      --execute immediate 'alter tablespace '||rects||' drop datafile '||recfid;2183      --exception when others then2184      null;2185    end;2186  end;21872188  procedure recover_truncated_table(tow           varchar2,2189                                    ttb           varchar2,2190                                    fbks          number default 1,2191                                    tmppath       varchar2 default null,2192                                    offline_files varchar2 default null) --'2193   as2194    tgtowner  varchar2(30) := upper(tow);2195    tgttable  varchar2(30) := upper(ttb);2196    tmpdir    varchar2(30);2197    rects     varchar2(30);2198    recfile   varchar2(30);2199    rstts     varchar2(30);2200    rstfile   varchar2(30);2201    blksz     number;2202    rectab    varchar2(30);2203    rsttab    varchar2(30);2204    copyfile  varchar2(30);2205    fy_ts_cnt number := 0;2206    endianess pls_integer;2207    temppath  varchar2(32767) := tmppath;2208  begin2209    select instr(platform_name, 'Windows')2210      into endianess2211      from v_$database2212     where rownum <= 1;2213    if temppath is null then2214      if endianess > 0 then2215        temppath := 'c:\temp\';2216      else2217        temppath := '/tmp/';2218      end if;2219    end if;2220    dbms_output.enable(999999);2221    tmpdir  := 'FY_DATA_DIR';2222    rects   := 'FY_REC_DATA';2223    rstts   := 'FY_RST_DATA';2224    recfile := 'FY_REC_DATA.DAT';2225    create_directory(temppath, tmpdir);2226    select count(*)2227      into fy_ts_cnt2228      from dba_tablespaces2229     where tablespace_name in (rects, rstts);2230    if fy_ts_cnt = 2 then2231      clean_up_ts(rects, rstts);2232      select substr(file_name,2233                    decode(instr(file_name, '\', -1),2234                           0,2235                           instr(file_name, '/', -1),2236                           instr(file_name, '\', -1)) + 1)2237        into recfile2238        from dba_data_files2239       where tablespace_name = rects2240         and rownum <= 1;2241    else2242      prepare_files(tgtowner,2243                    tgttable,2244                    temppath,2245                    rects,2246                    recfile,2247                    rstts,2248                    rstfile,2249                    blksz);2250    end if;2251    select block_size2252      into blksz2253      from dba_tablespaces ts, dba_tables t2254     where ts.tablespace_name = t.tablespace_name2255       and t.owner = tgtowner2256       and t.table_name = tgttable;2257    fill_blocks(tgtowner,2258                tgttable,2259                tmpdir,2260                rects,2261                recfile,2262                rstts,2263                8,2264                tgtowner,2265                tgtowner,2266                rectab,2267                rsttab,2268                copyfile);2269    recover_table(tgtowner,2270                  tgttable,2271                  tgtowner,2272                  rectab,2273                  tgtowner,2274                  rsttab,2275                  tmpdir,2276                  recfile,2277                  copyfile,2278                  blksz,2279                  fbks,2280                  'myself',2281                  offline_files);2282    log('Data has been recovered to ' || tgtowner || '.' || rsttab);2283    --execute immediate 'DROP TABLESPACE '||rects||' INCLUDING CONTENTS AND DATAFILES ';2284    --execute immediate 'DROP TABLESPACE '||rstts||' INCLUDING CONTENTS AND DATAFILES ';2285    --remove_file(tmpdir,recfile);2286    --remove_file(tmpdir,rstfile);2287    remove_file(tmpdir, copyfile);2288    -- execute immediate 'DROP DIRECTORY '||tmpdir;2289  end;22902291begin2292  null;2293end FY_Recover_Data;2294/2295

          

    本文结束。


    • 个人博客地址:www.xmmup.com

    • 微信公众号:DB宝,作者:小麦苗,作者微信:db_bao

    • 作者博客地址:http://blog.itpub.net/26736162/

    • 作者QQ:646634621,QQ群:230161599、618766405
    • 提供Oracle OCP、OCM、高可用(rac+dg+ogg)、MySQL DBA和PostgreSQL DBA培训
    • 版权所有,欢迎分享本文,转载请保留出处

    • 若有侵权请联系小麦苗删除

      ★DB宝分享的IT资料:https://mp.weixin.qq.com/s/Iwsy-zkzwgs8nYkcMz29ag
      ★DB宝笔试面试详解:https://mp.weixin.qq.com/s/Vm5PqNcDcITkOr9cQg6T7w

      长按下图识别二维码,关注小麦苗的微信公众号:DB宝,学习最实用的数据库技术。

      文章转载自DB宝,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

      评论