简体   繁体   English

如果出现错误,如何使DBMS_DATAPUMP错误?

[英]How do you make DBMS_DATAPUMP error if there's an error?

DBMS_DATAPUMP doesn't fail when the columns in the source and destination tables do not match. 当源表和目标表中的列不匹配时,DBMS_DATAPUMP不会失败。 This means that no exceptions are raised. 这意味着不会引发任何异常。 I'm trying to use the GET_STATUS procedure in order to understand if there are any errors but unfortunately there doesn't seem to be... 我正在尝试使用GET_STATUS程序,以了解是否有任何错误,但遗憾的是似乎没有......

My ultimate goal is for DBMS_DATAPUMP to raise an exception if the import fails. 我的最终目标是DBMS_DATAPUMP在导入失败时引发异常。 Differing columns is an easy example to work with as I know that it should fail. 不同的列是一个简单的例子,因为我知道它应该失败。

Here's my current code (I've obscured schema names purposefully). 这是我当前的代码(我故意模糊了模式名称)。 The environment I'm using is identical on both servers save that I've added an extra column to the source table. 我正在使用的环境在两台服务器上是相同的,除了我已经在源表中添加了一个额外的列。 I also perform a count of the number of rows in the table. 我还执行表中行数的计数。

connect schema/*@db1/db1
-- */

create table tmp_test_datapump as
 select u.*, cast(null as number) as break_it
   from user_tables u;

Table created.


select count(*) from tmp_test_datapump;

  COUNT(*)
----------
      1170

connect schema/*@db2/db2
-- */

set serveroutput on

create table tmp_test_datapump as
 select u.*
   from user_tables u;

Table created.

In attempting to test this the DATAPUMP code has got a little more complicated. 在尝试测试时,DATAPUMP代码有点复杂。 Everything in the infinite loop can be removed and this would act the same. 可以删除无限循环中的所有内容,这将起到相同的作用。

declare
   l_handle number;
   l_status varchar2(255);
   l_job_state varchar2(4000);
   l_ku$status ku$_status1020;
begin
   l_handle := dbms_datapump.open( operation => 'IMPORT'
                                 , job_mode => 'TABLE'
                                 , remote_link => 'SCHEMA.DB.DOMAIN.COM'
                                 , job_name => 'JOB_TEST_DP'
                                 , version => 'COMPATIBLE' );
   dbms_datapump.set_parameter( handle => l_handle
                              , name => 'TABLE_EXISTS_ACTION'
                              , value => 'TRUNCATE');
   dbms_datapump.metadata_filter( handle => l_handle
                                , name => 'NAME_EXPR'
                                , value => 'IN (''TMP_TEST_DATAPUMP'')');
   dbms_datapump.start_job(handle => l_handle);

   while true loop
      dbms_datapump.wait_for_job(handle => l_handle,job_state => l_status);

      if l_status in ('COMPLETED','STOPPED') then
         exit;
      end if;

      dbms_datapump.get_status( handle => l_handle
                              , mask => dbms_datapump.KU$_STATUS_JOB_ERROR
                              , job_state => l_job_state
                              , status => l_ku$status);
      dbms_output.put_line('state: ' || l_job_state);
      if l_ku$status.error is not null and l_ku$status.error.count > 0 then

         for i in l_ku$status.error.first .. l_ku$status.error.last loop
            dbms_output.put_line(l_ku$status.error(i).logtext);
         end loop;
       end if;
   end loop;

end;
/

PL/SQL procedure successfully completed.

select count(*) from tmp_test_datapump;

  COUNT(*)
----------
        47

As you can see the number of records in the tables is different; 如您所见,表中的记录数量不同; the import has failed and no exception has been raised. 导入失败,没有例外。 Various blogs and DBA.SE questions imply that some sort of error catching can be done; 各种 博客DBA.SE问题意味着可以进行某种错误捕获; but I can't seem to manage it. 但我似乎无法管理它。

How can you catch fatal errors in a DBMS_DATAPUMP import? 如何在DBMS_DATAPUMP导入中捕获致命错误?

I'm working with dbms_datapump package right know. 我正在使用dbms_datapump包知道。 The following procedure is searching one table for schemas that will be exported. 以下过程在一个表中搜索将要导出的模式。 BACKUP_INFO_MOD is a procedure with PRAGMA AUTONOMOUS TRANSACTION that's making logs in another table. BACKUP_INFO_MOD是一个PRAGMA AUTONOMOUS TRANSACTION的程序,它在另一个表中创建日志。
Example 6.3 from this document helped me a lot. 本文档中的示例6.3对我帮助很大。 Here's fragment from my code (with additional commentary): 这是我的代码中的片段(附加注释):

  CREATE OR REPLACE PROCEDURE BACKUP_EXECUTE (
    threads in number := 1 
  , dir in varchar2 := 'DATA_PUMP_DIR'
  ) AS 
    schemas varchar2(255);
    filename varchar2(255);
    path varchar2(255);
    errormsg varchar2(4000);

    handle number;
    job_state varchar2(30);
    --variables under this line are important to error handling
    logs ku$_LogEntry;
    lindx pls_integer;
    status ku$_Status;

    exporterr exception; --our exception to handle export errors

    [...]
  BEGIN    
    [...]
        schemas:=schema_list(indx).schema_name;

        --Full dir path for logs
        select directory_path into path from dba_directories where directory_name=dir;
        --If data not found then automatically raise NO_DATA_FOUND

        select to_char(sysdate, 'YYMMDDHH24MI-')||lower(schemas)||'.dmp' into filename from dual;

        backup_info_mod('insert',path||filename,schemas);

        begin --For inner exception handling on short fragment
          handle := dbms_datapump.open('EXPORT','SCHEMA');
          dbms_datapump.add_file(handle, filename, dir); --dump file
          dbms_datapump.add_file(handle, filename||'.log', dir,null,DBMS_DATAPUMP.KU$_FILE_TYPE_LOG_FILE); --export log file
          dbms_datapump.metadata_filter(handle, 'SCHEMA_EXPR', 'IN ('''||schemas||''')');
          dbms_datapump.set_parallel(handle,threads);

          backup_info_mod(file_name=>path||filename, curr_status=>'IN PROGRESS');

          dbms_datapump.start_job(handle);

        --If job didn't start due to some errors, then let's get some information
        exception
          when others then
            dbms_datapump.get_status(handle,8,0,job_state,status);
        --This will overwrite our job_state and status
        end;

        --Let's go handle error if job_state was overwritten
        if job_state is not null then
          raise exporterr;
        else
          job_state:='UNDEFINED';
        end if;

        --Checking in loop if errors occurred. I'm not using wait_for_job
        --because it didn't work out
        while (job_state != 'COMPLETED') and (job_state != 'STOPPED') loop
        --Like before, let's get some information
          dbms_datapump.get_status(handle,8,-1,job_state,status);

        --Looking for errors using mask
          if (bitand(status.mask,dbms_datapump.ku$_status_job_error) != 0) then          
        --If occurred: let's stop the export job and raise an error
            dbms_datapump.stop_job(handle);
            dbms_datapump.detach(handle);
            raise exporterr;
          exit;

          end if;
        end loop;

        backup_info_mod(file_name=>path||filename, curr_status=>'COMPLETED');

        dbms_datapump.detach(handle);

      exception
        when NO_DATA_FOUND then
          backup_info_mod('insert',null,schemas,'ERROR','No '||dir||' defined in dba_directories');

        when exporterr then
        --Let's get all error messages and write it to errormsg variable
          logs:=status.error;
          lindx:=logs.FIRST;

          while lindx is not null loop
            errormsg:=errormsg||logs(lindx).LogText;
            lindx:=logs.NEXT(lindx);

            if lindx is not null then
              errormsg:=errormsg||' | '; --Just to separate error messages
            end if;
          end loop;

          backup_info_mod(
            file_name=>path||filename,
            curr_status=>'ERROR',
            errormsg=>errormsg);

        /*when other then --TODO
          null;
          */
      end;

  END BACKUP_EXECUTE;

在为impdp创建日志时,可以将datapump命令放在shell脚本中,在结束shell脚本之前,可以检查日志中的IMP-错误或ORA-错误,如果为true则警告用户查看日志文件错误。

The provided document from yammy is good. yammy提供的文件很好。

I faced the same problem when using the dbms_datapump package to import a DB dump. 使用dbms_datapump包导入数据库转储时遇到了同样的问题。 Even there are error during the import, the job is treated as success / finished. 即使导入期间出错,该作业也会被视为成功/完成。 By using the code example in the document , i could get the error / log message during the import. 通过使用文档中的代码示例,我可以在导入期间获取错误/日志消息。 I then check if there are 'ORA-' found in the log message and throw a custom error when the import job is finished. 然后检查日志消息中是否找到“ORA-”并在导入作业完成时抛出自定义错误。

Following is the sample code: 以下是示例代码:

PROMPT CREATE OR REPLACE PROCEDURE import_schema

CREATE OR REPLACE PROCEDURE import_db_dump (
    dumpFilename        IN VARCHAR2)
IS
    handle NUMBER;              -- Handler of the job
    loopIdx NUMBER;             -- Loop index
    percentDone NUMBER;         -- Percentage of job complete
    jobState VARCHAR2(30);      -- To keep track of job state
    ku_logEntry ku$_LogEntry;   -- For WIP and error messages
    ku_jobStatus ku$_JobStatus; -- The job status from get_status
    ku_jobDescjd ku$_JobDesc;   -- The job description from get_status
    ku_Status ku$_Status;       -- The status object returned by get_status

    errorCount          NUMBER;
    import_error_found  EXCEPTION;

BEGIN
    handle := dbms_datapump.open (
    operation =>    'IMPORT',
    job_mode =>     'SCHEMA');

    dbms_output.put_line('Define table exists action: truncate');
    dbms_datapump.set_parameter (
        handle =>   handle,
        name =>     'TABLE_EXISTS_ACTION',
        value =>    'TRUNCATE');

    dbms_output.put_line('Define dumpfilename: ' || dumpFilename);
    dbms_datapump.add_file (
        handle =>       handle,
        filename =>     dumpFilename,
        filetype =>     dbms_datapump.ku$_file_type_dump_file);

    dbms_output.put_line('Start datapump job');
    dbms_output.put_line('==================');
    dbms_datapump.start_job (handle);

    -- Ref: http://docs.oracle.com/cd/E11882_01/server.112/e22490/dp_api.htm#SUTIL977

    -- The import job should now be running. In the following loop, the job is
    -- monitored until it completes. In the meantime, progress information is
    -- displayed.

    percentDone := 0;
    jobState := 'UNDEFINED';
    errorCount := 0;
    WHILE (jobState != 'COMPLETED') AND (jobState != 'STOPPED') LOOP
        dbms_datapump.get_status(handle,
               dbms_datapump.ku$_status_job_error +
               dbms_datapump.ku$_status_job_status +
               dbms_datapump.ku$_status_wip,
               -1, jobState, ku_Status);
        ku_jobStatus := ku_Status.job_status;

        -- If the percentage done changed, display the new value.
        IF ku_jobStatus.percent_done != percentDone THEN
          dbms_output.put_line('*** Job percent done = ' ||
                               to_char(ku_jobStatus.percent_done));
          percentDone := ku_jobStatus.percent_done;
        END IF;

        -- If any work-in-progress (WIP) or Error messages were received for the job,
        -- display them.

        IF (bitand(ku_Status.mask, dbms_datapump.ku$_status_wip) != 0) THEN
            ku_logEntry := ku_Status.wip;
        ELSE
            IF (bitand(ku_Status.mask,dbms_datapump.ku$_status_job_error) != 0) THEN
                ku_logEntry := ku_Status.error;
            ELSE
                ku_logEntry := null;
            END IF;
        END IF;

        IF ku_logEntry IS NOT NULL THEN
            loopIdx := ku_logEntry.FIRST;
            WHILE loopIdx IS NOT NULL LOOP
                dbms_output.put_line(ku_logEntry(loopIdx).LogText);
                IF INSTR(ku_logEntry(loopIdx).LogText, 'ORA-') > 0 THEN
                    errorCount := errorCount + 1;
                    dbms_output.put_line('^^^^---ERROR FOUND');
                END IF;
                loopIdx := ku_logEntry.NEXT(loopIdx);
            END LOOP;
        END IF;

    END LOOP;

    -- Indicate that the job finished and gracefully detach from it.
    dbms_output.put_line('Job has completed');
    dbms_output.put_line('Final job state = ' || jobState);
    dbms_datapump.detach(handle);

    IF errorCount > 0 THEN
        RAISE import_error_found;
    END IF;

EXCEPTION
    WHEN import_error_found THEN
        dbms_output.put_line('Error found when import. Number of error: ' || errorCount);
        RAISE;

    WHEN OTHERS THEN
        dbms_output.put_line('[Error Backtrace]');
        dbms_output.put_line(dbms_utility.format_error_backtrace());
        dbms_output.put_line('[Call Stack]');
        dbms_output.put_line(dbms_utility.format_call_stack());

        dbms_datapump.stop_job(handle);
        RAISE;
END;
/

Hope this help. 希望这有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM