oracle如何在过程/包中找到begin的行号

时间:2014-06-02 11:48:20

标签: oracle stored-procedures plsql oracle11g

我希望在每个过程,函数和打包过程的开头之后添加一些代码,我有成千上万的程序,软件包等,所以手动执行此操作需要花费数周的时间。

我可以搜索all_source但是在我自己编写之前有人有任何分析代码来查找“开始”的行号,因为可能存在我需要忽略的子例程或匿名块

例如来自user_source

package body my_pck is
  procedure proc1 
  is
    v_var varchar2(10);
    procedure sub_proc
    is
    begin
      some code ....
    end;
  begin
< I want to insert code here>
    some code ....

    begin
      anon block ....
    end;
  end;
  procedure proc2 
  is
    v_var varchar2(10);
    procedure sub_proc_something_else
    is
    begin
      some code ....
    end;
    procedure sub_proc_another
    is
    begin
      some code ....
    end;
  begin
< I want to insert code here as well>
    some code ....
  end;
end;

所以我我需要一个例程来匹配开始/结束以找到添加我的代码的位置

由于 罗伯特

3 个答案:

答案 0 :(得分:1)

你肯定需要一个解析器来完成这项任务。我为Vorax创建了一个plsql解析器,如果你愿意,可以使用它。它不是一个完整的解析器,但足够聪明,可以找出plsql代码的结构。

从github获取vorax4项目。

cd C:\Projects
git clone https://github.com/talek/vorax4
gem install vorax

编写一个简单的ruby代码来处理您的场景:

$LOAD_PATH << 'C:/Projects/vorax4/vorax/ruby/lib/'

require 'vorax.rb'
include Vorax

# You need to get this from your database
package_source =<<EOF

package body my_pck is
  procedure proc1 
  is
    v_var varchar2(10);
    procedure sub_proc
    is
    begin
      some code ....
    end;
  begin
    some code ....

    begin
      anon block ....
    end;
  end;
  procedure proc2 
  is
    v_var varchar2(10);
    procedure sub_proc_something_else
    is
    begin
      some code ....
    end;
    procedure sub_proc_another
    is
    begin
      some code ....
    end;
  begin
    some code ....
  end;
end;

EOF

structure = Parser::PlsqlStructure.new(package_source)

# just print the structure of the package
puts structure.dump

# the code we want to insert
offset = 0
INSERT_CODE = "\n--my code\n"
INSERT_CODE_LEN = INSERT_CODE.length

# loop into the plsql structure
structure.regions.each do |child|

  region = child.content

  # only if it's a procedure/function declared into the body of the package
  if region && child.level == 2 && region.instance_of?(Parser::SubprogRegion)
    pos_to_insert = offset + region.body_start_pos + 'begin'.length

    # insert the code after the BEGIN clause
    package_source.insert(pos_to_insert, INSERT_CODE)

    # adjust the offset
    offset += INSERT_CODE_LEN + 1
  end

end

# print the new version of the package
puts package_source

输出结果为:

[Level: 0]
  [Level: 1] PackageBodyRegion: {:start_pos=>2, :end_pos=>467, :name=>"my_pck", :name_pos=>15, :signature_end_pos=>24, :declare_end_pos=>462}
    [Level: 2] SubprogRegion: {:start_pos=>27, :end_pos=>217, :name=>"proc1", :name_pos=>37, :body_start_pos=>145}
      [Level: 3] SubprogRegion: {:start_pos=>77, :end_pos=>141, :name=>"sub_proc", :name_pos=>87, :body_start_pos=>107}
      [Level: 3] AnonymousRegion: {:start_pos=>175, :end_pos=>210}
    [Level: 2] SubprogRegion: {:start_pos=>221, :end_pos=>462, :name=>"proc2", :name_pos=>231, :body_start_pos=>432}
      [Level: 3] SubprogRegion: {:start_pos=>271, :end_pos=>350, :name=>"sub_proc_something_else", :name_pos=>281, :body_start_pos=>316}
      [Level: 3] SubprogRegion: {:start_pos=>356, :end_pos=>428, :name=>"sub_proc_another", :name_pos=>366, :body_start_pos=>394}

package body my_pck is
  procedure proc1
  is
    v_var varchar2(10);
    procedure sub_proc
    is
    begin
      some code ....
    end;
  begin

--my code
    some code ....

    begin
      anon block ....
    end;
  end;
  procedure proc2
  is
    v_var varchar2(10);
    procedure sub_proc_something_else
    is
    begin
      some code ....
    end;
    procedure sub_proc_another
    is
    begin
      some code ....
    end;
  begin

--my code
   some code ....
  end;
end;

其他解析器选项虽然我没有使用过,但可能是:

答案 1 :(得分:-1)

我认为这很难(但并非不可能)。首先,您需要从数据库中获取包。我得到了一些可以做到这一点的代码:

DECLARE
  package_name user_source.name%type;
  last_package_name user_source.name%type;
  package_body CLOB;
BEGIN
  FOR package_cur IN
  ( SELECT * FROM user_source WHERE type = 'PACKAGE BODY' ORDER BY name, line
  )
  LOOP
    package_name        := package_cur.name;
    IF last_package_name = package_name OR last_package_name IS NULL THEN
      package_body      := package_body || package_cur.text;
    ELSE
      --=======================================================
      -- whole package is now in package_body and can be altered
      --=======================================================
      insert into tmp_table values (package_body);

      -- move to next package
      package_body := package_cur.text;
    END IF;
    last_package_name := package_name;
  END LOOP;
  -- processing very last package
  insert into tmp_table values (package_body);
END;

下一个障碍是代码可以用各种方式概述,因为我知道整个包可以写成一行。您必须找出一种或另一种方法来首先从包中提取所有过程,然后绑定相应的begin关键字。

答案 2 :(得分:-2)

使用$$ PLSQL_LINE。另请参阅$$ PLSQL_UNIT。

BEGIN
  DBMS_OUTPUT.PUT_LINE ( $$PLSQL_UNIT || '.' || $$PLSQL_LINE || ': hello ' );
END;
/