在特定模式的源代码中搜索(PL / SQL)

时间:2016-02-22 10:17:31

标签: sql oracle search plsql sql-like

在源代码中,如果我想查找某些内容,请说明特定列的更新位置。我使用以下查询来查找表(LEA_AGREEMENT_DTL)的列(BUCKET)的更新位置。

select * from user_source where upper(text) like '%UPDATE%LEA_AGREEMENT_DTL%BUCKET%';

现在,如果该特定编码中的源代码编写如下,我的查询将告诉我编写代码的过程:

  Update Lea_agreement_dtl Set Dpd = No_Days_OverDuE,  bucket=V_bucket
   where ProposalID = T_ProposalID;

但如果代码编写如下,我的查询将不会给出任何结果:

    Update Lea_agreement_dtl 
  Set Dpd = No_Days_OverDuE,  
  bucket=V_bucket
  where ProposalID = T_ProposalID;

我的问题是如何修改我的查询以搜索特定架构/用户的源代码,以便在两种情况下都获得成功结果。基本上我想找到在该特定模式中更新此列的所有过程/对象。

根据我的分析,如果整个查询都写在一行中,那么我可以搜索它,否则它不起作用。

2 个答案:

答案 0 :(得分:0)

这个问题有三种主要方法:

  1. 与字符串函数和正则表达式一起破解。这是最常见的解决方案,但也充满漏洞。根据您搜索代码的原因,这些漏洞可能无关紧要。这足以找到开始编码的位置,但可能不足以向某人证明代码被覆盖。
  2. 对输入进行标记并循环遍历寻找模式的标记。词法分析器可以处理单个正则表达式不易处理的一些问题,例如注释和备用引用语法。通过对Oracle语法的深入理解,可以构建高度精确的解决方案。它仍然会遗漏极其破碎的代码(例如,可以使用UPDATE创建代码作为变量),动态SQL以及通过同义词和视图的递归引用。
  3. 解析输入并走一个抽象语法树寻找模式。这将是一个很好的100%准确的解决方案。不幸的是,PL / SQL中没有高质量的PL / SQL解析器。
  4. 下面的解决方案使用我创建的open-source PL/SQL lexer来解决这样的问题。

    示例程序

    字符串模式UPDATE-LEA_AGREEMENT_DTL-BUCKET出现三次以下。但只有第4行的第一个UPDATE才真正满足条件。 (第三次更新在Stackoverflow语法高亮显示中可能看起来很奇怪,但在实际的PL / SQL中,第二个引号不会关闭字符串。)

    create or replace procedure search_test is
    begin
      --Real match.
      Update Lea_agreement_dtl Set Dpd = No_Days_OverDuE,
       bucket=V_bucket
       where ProposalID = T_ProposalID;
    
      --Exclude - ignore comments.
      /*Update Lea_agreement_dtl Set Dpd = No_Days_OverDuE,  bucket=V_bucket
       where ProposalID = T_ProposalID;*/
    
      --Exclude - watch out for alternative quoting syntax. 
      Update Lea_agreement_dtl Set Dpd = q'[No_Days_OverDuE',  bucket=V_bucket ]'
       where ProposalID = T_ProposalID;
    end;
    /
    

    查找行的匿名阻止

    --Find lines that update LEA_AGREEMENT_DTL.BUCKET.
    --Does not search dynamic SQL and does not recurse through view or synonyms.
    declare
        v_tokens token_table;
    
        v_update_line_number number;
        v_has_update boolean := false;
        v_has_table boolean := false;
        v_has_column boolean := false;
    begin
        --Get source and tokenize it.
        v_tokens := tokenizer.tokenize(dbms_metadata.get_ddl('PROCEDURE', 'SEARCH_TEST'));
    
        --Loop through tokens and look for UPDATE/LEA_AGREEMENT_DTL/BUCKET between semicolons.
        for i in 1 .. v_tokens.count loop
            --Reset if a semicolon is found.
            if v_tokens(i).value = ';' then
                v_has_update := false;
                v_has_table := false;
                v_has_column := false;
            --Look for relevant tokens, in order.
            elsif upper(v_tokens(i).value) = 'UPDATE' then
                v_update_line_number := v_tokens(i).line_number;
                v_has_update := true;
            elsif v_has_update and upper(v_tokens(i).value) = 'LEA_AGREEMENT_DTL' then
                v_has_table := true;
            elsif v_has_table and upper(v_tokens(i).value) = 'BUCKET' then
                v_has_column := true;
            end if;
    
            --Success if all conditions are met.
            if v_has_update and v_has_table and v_has_column then
                --Subtract 1 because DBMS_METADATA put a blank line at the beginning.
                dbms_output.put_line('Found on line '||to_char(v_update_line_number-1));
                v_has_update := false;
                v_has_table := false;
                v_has_column := false;
            end if;
    
        end loop;
    end;
    /
    

    <强>结果

    Found on line 4
    

答案 1 :(得分:0)

您可以使用此view

CREATE OR REPLACE VIEW V_UPDATE_USER_SOURCE AS
SELECT TYPE,
           NAME,
           line,
           LISTAGG(regexp_replace(text,'[[:space:]]',' '), ' ') WITHIN GROUP(ORDER BY norder) text
      FROM (SELECT a.TYPE,
                   a.NAME,
                   a.line,
                   b.text,
                   b.line norder
              FROM (SELECT line,
                           TYPE,
                           NAME,
                           text
                      FROM user_source
                     WHERE regexp_like(text, '[[:space:]]update[[:space:]]', 'i')) a,
                   user_source b
             WHERE a.type = b.TYPE
               AND a.name = b.name
               AND b.line BETWEEN a.line AND (SELECT MIN(g.line)
                                                FROM user_source g
                                               WHERE regexp_like(g.TEXT, ';', 'i')
                                                 AND g.TYPE = a.TYPE
                                                 AND g.NAME = a.name
                                                 AND g.line >= a.line)
             ORDER BY b.TYPE,
                      b.NAME,
                      b.line) c
     GROUP BY TYPE,
              NAME,
              line

LISTAGG致力于Oracle 11g或更高版本。 如果您使用以前版本的Oracle,则需要此view

CREATE OR REPLACE VIEW V_UPDATE_USER_SOURCE AS
SELECT TYPE,
         NAME,
         line,
         XMLAGG(XMLELEMENT(E, regexp_replace(text, '[[:space:]]', ' ') || ' ')).EXTRACT('//text()') text
FROM (SELECT a.TYPE,
                         a.NAME,
                         a.line,
                         b.text,
                         b.line norder
                FROM (SELECT line,
                                         TYPE,
                                         NAME,
                                         text
                                FROM user_source
                             WHERE regexp_like(text, '[[:space:]]update[[:space:]]', 'i')) a,
                         user_source b
             WHERE a.type = b.TYPE
                 AND a.name = b.name
                 AND b.line BETWEEN a.line AND (SELECT MIN(g.line)
                                                                                    FROM user_source g
                                                                                 WHERE regexp_like(g.TEXT, ';', 'i')
                                                                                     AND g.TYPE = a.TYPE
                                                                                     AND g.NAME = a.name
                                                                                     AND g.line >= a.line)
             ORDER BY b.TYPE,
                                b.NAME,
                                b.line)
       GROUP BY TYPE,
                NAME,
                line;

它返回数据集,其中包含updateupdate开始的数字一致的所有View

select * from V_UPDATE_USER_SOURCE t where regexp_like(text,'clients.*STATE','i') 可与regexp_like一起使用:

List<Currency> currencyList

说明

  • 客户 - 表。
  • 状态 - 要更新的列。