標準愚痴出力

個人的なIT作業ログです。もしかしたら一般的に参考になることが書いているかもしれません(弱気

Oracle のダンプファイルから、インポートせずに SQL のみを抽出する

imp ユーティリティーの SHOW=Y オプションを使うとインポートは行わず、インポート時に発行される SQL のみが標準エラー出力に出力される。

imp システムユーザ名/パスワード file=ダンプファイル名 fromuser=(エクスポート時のユーザ) touser=(インポート先ユーザ) rows=N show=y 2>the.sql

ただし、これだと、次のように SQL の途中に勝手に改行が入り、かつ前後に二重引用符が補われてしまう。

. BBBBBBのオブジェクトをBBBBBBにインポートしています
 "BEGIN  "
 "sys.dbms_logrep_imp.instantiate_schema(schema_name=>SYS_CONTEXT('USERENV','"
 "CURRENT_SCHEMA'), export_db_name=>'BBBBBB.WORLD', inst_scn=>'199195734');"
 "COMMIT; END;"

これでは使えないので、

  • 前後の二重引用符を取り除く
  • シングルクォートで囲まれた文字列が複数行に分かれてしまっている場合は一行に結合する

といったことを行う Perl スクリプトを用意した。 (PerlOracle に標準でついてくる)

use strict;
use warnings;

my $stock="";
my $last="";

while ( <> ){
    chomp;
    if ( /^ "(.*)"$/ ){
        $stock .= $1;
        my $q = 0; $q++ while $stock =~ /'/g;
        if ( $q % 2 == 0 ){
            if ( $stock =~ /^\s*ALTER/ || $stock =~ /^\s*CREATE/ ){
                print ";" if $last !~ /;\s*$/;
                print "\n\n";
            }
            print $stock;
            $last = $stock;
            $stock = "";
        }
    }
}
if ( $stock ne "" ){
    print $stock,"\n";
}

(修正:最初文字のカウントに split を使っていたが、while m/~/g を使うよう修正した)

perl.exe log2sql.pl the.sql > new.sql を実行すると、

次のように出力される。

BEGIN  
sys.dbms_logrep_imp.instantiate_schema(schema_name=>SYS_CONTEXT('USERENV','CURRENT_SCHEMA'), export_db_name=>'BBBBBB.WORLD', inst_scn=>'199195734');
COMMIT; END;