PL/SQLのリファクタリングの2
最初の一歩として、まずは個々の処理毎に分割してみた。
結果はこんな感じ。
create or replace package 月次処理
is
  PKG_NM constant varchar2(30) := '月次処理' ;
  --
  function 当月分コピー return number ;
  --
  function 納品コピー(
     p_bgn in date
   , p_end in date
  ) return number ;
  --
  function 返品コピー(
     p_bgn in date
   , p_end in date
  ) return number ;
  --
  procedure ログ出力(
     p_fnc in バッチログ.処理モジュール%type
   , p_sts in バッチログ.処理状況%type
   , p_cnt in バッチログ.処理件数%type
   , p_msg in バッチログ.補足事項%type
  ) ;
end ;
/
create or replace package body 月次処理
is
  function 当月分コピー return number
  is
    FNC_NM constant varchar2(30) := '当月分コピー' ;
    FIN_DT constant number       := 15 ;
    v_bgn  date ;
    v_end  date ;
    v_cnt  number := 0 ;
  begin
    ログ出力(
       PKG_NM || '.' || FNC_NM
     , '処理開始'
     , 0
     , null
    ) ;
    --
    v_bgn := add_months( trunc( sysdate, 'MONTH' ), -1 ) + FIN_DT ; -- 先月16日00:00:00
    v_end := add_months( v_bgn, 1 ) - 1 / ( 24 * 60 * 60 ) ;        -- 当月15日23:59:59
    --
    v_cnt := v_cnt + 納品コピー( v_bgn, v_end ) ;
    v_cnt := v_cnt + 返品コピー( v_bgn, v_end ) ;
    commit ;
    --
    ログ出力(
       PKG_NM || '.' || FNC_NM
     , '正常終了'
     , v_cnt
     , null
    ) ;
    --
    return 0 ;
  exception
    when others then
      rollback ;
      dbms_output.put_line( dbms_utility.format_error_stack() );
      dbms_output.put_line( dbms_utility.format_error_backtrace() );
      --
      ログ出力(
         PKG_NM || '.' || FNC_NM
       , '異常終了'
       , 0
       , sqlerrm
      ) ;
      return 1 ;
  end ;
  --
  function 納品コピー(
     p_bgn in date
   , p_end in date
  ) return number
  is
    FNC_NM constant varchar2(30) := '納品コピー' ;
    v_cnt  number := 0 ;
  begin
    ログ出力(
       PKG_NM || '.' || FNC_NM
     , '処理開始'
     , 0
     , null
    ) ;
    --
    insert into 月次納品 (
       ISBN
     , 納品先ID
     , 工場出荷日
     , 納品予定日
     , 納品実績日
     , 価格
    )
    select
       ISBN
     , 納品先ID
     , 工場出荷日
     , 納品予定日
     , 納品実績日
     , 価格
    from
       日次納品
    where
       納品実績日 between p_bgn and p_end
    ;
    v_cnt := sql%rowcount ;
    --
    ログ出力(
       PKG_NM || '.' || FNC_NM
     , '正常終了'
     , v_cnt
     , null
    ) ;
    return v_cnt ;
  exception
    when others then
      raise ;
  end ;
  --
  function 返品コピー(
     p_bgn in date
   , p_end in date
  ) return number
  is
    FNC_NM constant varchar2(30) := '返品コピー' ;
    v_cnt  number := 0 ;
  begin
    ログ出力(
       PKG_NM || '.' || FNC_NM
     , '処理開始'
     , 0
     , null
    ) ;
    --
    insert into 月次返品 (
       ISBN
     , 納品先ID
     , 返品予定日
     , 返品実績日
     , 払戻価格
     , 負担割合
     , 返品理由
    )
    select
       ISBN
     , 納品先ID
     , 返品予定日
     , 返品実績日
     , 払戻価格
     , 負担割合
     , 返品理由
    from
       日次返品
    where
       返品実績日 between p_bgn and p_end
    ;
    v_cnt := sql%rowcount ;
    --
    ログ出力(
       PKG_NM || '.' || FNC_NM
     , '正常終了'
     , v_cnt
     , null
    ) ;
    return v_cnt ;
  exception
    when others then
      raise ;
  end ;
  --
  procedure ログ出力(
     p_fnc in バッチログ.処理モジュール%type
   , p_sts in バッチログ.処理状況%type
   , p_cnt in バッチログ.処理件数%type
   , p_msg in バッチログ.補足事項%type
  )
  is
    pragma AUTONOMOUS_TRANSACTION ;
    PRC_NM constant varchar2(30) := 'ログ出力' ;
  begin
    insert into バッチログ (
       日時
     , 処理モジュール
     , 処理状況
     , 処理件数
     , 補足事項
    ) values (
       systimestamp
     , p_fnc
     , p_sts
     , p_cnt
     , p_msg
    ) ;
    commit ;
  exception
    when others then
      rollback ;
      dbms_output.put_line( dbms_utility.format_error_stack() );
      dbms_output.put_line( dbms_utility.format_error_backtrace() );
  end ;
end ;
/
機能本体としては以下の3つ。
- 全体の制御
 - 納品コピー
 - 返品コピー
 
その他、共通処理としてログ出力。
リファクタリングとは 「振る舞いを変えずにコードを綺麗にすること」 だが、振る舞いは微妙に変えている。 各機能モジュール内でも開始/終了のログを出すようにしたり、ログを独立したトランザクションにしたり。 でも本来の機能については変わらないし、他に適当な言葉もないし、これもリファクタリングでいいだろう。
で、結果を眺めていて気になるのがログ出力の部分。
開始と正常終了と異常終了はパラメーターが違うだけなので共通化してみたのだが、そのために常に使わないパラメーターまで指定しなければいけないことになっている。 逆に、種別に関係なく常に同じ値を設定というか使っているパラメーターもある。 具体的にはパッケージ名。 現状は日時だけを共通モジュール内に隠蔽しているが、パッケージ名もそうしたい。
ということで、明日はログ周りをなんとかしてみる。